@xopcai/xopc 0.0.110 → 0.0.111

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 (301) hide show
  1. package/README.md +46 -4
  2. package/README.zh-CN.md +46 -4
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/telegram/xopc.extension.json +1 -1
  5. package/dist/gateway/static/root/assets/Combination-BzaXOLd9.js +41 -0
  6. package/dist/gateway/static/root/assets/agent-avatar-dicebear-zlx9l5Yp.js +1 -0
  7. package/dist/gateway/static/root/assets/agent-browser-settings-page-B-0zGjt8.js +6 -0
  8. package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-Bz7JWjRM.js +1 -0
  9. package/dist/gateway/static/root/assets/agents-DwDnJlXT.js +71 -0
  10. package/dist/gateway/static/root/assets/app-management-settings-panel-DaQwdeCq.js +1 -0
  11. package/dist/gateway/static/root/assets/appearance-settings-D2zv6r3P.js +1 -0
  12. package/dist/gateway/static/root/assets/apps-page-BIppe_jj.js +1 -0
  13. package/dist/gateway/static/root/assets/archive-plugin-DEmu8eH7.js +1 -0
  14. package/dist/gateway/static/root/assets/attachment-load-B98lJoN5.js +2 -0
  15. package/dist/gateway/static/root/assets/{attachment-preview-renderer-CybMSIoS.js → attachment-preview-renderer-DonnL2dL.js} +1 -1
  16. package/dist/gateway/static/root/assets/binary-plugins-CL9QKmyo.js +2 -0
  17. package/dist/gateway/static/root/assets/block-editor-BOAhMAhT.js +180 -0
  18. package/dist/gateway/static/root/assets/channels-settings-Br8iRnXp.js +1 -0
  19. package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +1 -0
  20. package/dist/gateway/static/root/assets/code-editor-dZTY2dRW.js +1 -0
  21. package/dist/gateway/static/root/assets/config-api-0o1WYdz2.js +3 -0
  22. package/dist/gateway/static/root/assets/connectors-settings-DDvHo9in.js +2 -0
  23. package/dist/gateway/static/root/assets/cron-api-Dj_UZKST.js +1 -0
  24. package/dist/gateway/static/root/assets/cron-dreaming-jobs-nCMWCf0p.js +1 -0
  25. package/dist/gateway/static/root/assets/cron-page-Dv7GII9G.js +1 -0
  26. package/dist/gateway/static/root/assets/cron-schedule-picker-DH10KgD6.js +1 -0
  27. package/dist/gateway/static/root/assets/dist-By6Rh2ee.js +1 -0
  28. package/dist/gateway/static/root/assets/dist-CkobR7mk.js +1 -0
  29. package/dist/gateway/static/root/assets/dist-DokQNVMQ.js +1 -0
  30. package/dist/gateway/static/root/assets/dreaming-scene-BHMRVEUS.js +4585 -0
  31. package/dist/gateway/static/root/assets/dreaming-settings-L2rgZDQl.js +1 -0
  32. package/dist/gateway/static/root/assets/extension-debug-page-Cjx6pZVz.js +1 -0
  33. package/dist/gateway/static/root/assets/{extension-page-W1wiG38F.js → extension-page-BSPNL90V.js} +1 -1
  34. package/dist/gateway/static/root/assets/extension-settings-page-m_UQYkVc.js +1 -0
  35. package/dist/gateway/static/root/assets/fetch-Bs7in_4F.js +1 -0
  36. package/dist/gateway/static/root/assets/format-interval-label-CftJ5uXu.js +1 -0
  37. package/dist/gateway/static/root/assets/gateway-config-api-Clfck-hW.js +1 -0
  38. package/dist/gateway/static/root/assets/gateway-settings-CS177xni.js +1 -0
  39. package/dist/gateway/static/root/assets/gateway-startup-retry-BkjVJc38.js +1 -0
  40. package/dist/gateway/static/root/assets/goal-detail-page-kqJue0sE.js +1 -0
  41. package/dist/gateway/static/root/assets/goals-page-C0FujUB5.js +2 -0
  42. package/dist/gateway/static/root/assets/goals-settings-CJnzNSDo.js +1 -0
  43. package/dist/gateway/static/root/assets/heartbeat-config-api-Cp7CPuIn.js +1 -0
  44. package/dist/gateway/static/root/assets/heartbeat-settings-ifSI1Wbh.js +1 -0
  45. package/dist/gateway/static/root/assets/html-workspace-editor-CQLWDiwE.js +1 -0
  46. package/dist/gateway/static/root/assets/index-COkF54xv.js +121 -0
  47. package/dist/gateway/static/root/assets/index-DIaSNGEO.css +1 -0
  48. package/dist/gateway/static/root/assets/interval-presets-B29Ss_2y.js +2 -0
  49. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings--MI1rYl7.js +1 -0
  50. package/dist/gateway/static/root/assets/locale-store-DjbfSsfA.js +1 -0
  51. package/dist/gateway/static/root/assets/logs-page-BwrVNlyW.js +2 -0
  52. package/dist/gateway/static/root/assets/markdown-editor-AssmZFx4.js +2 -0
  53. package/dist/gateway/static/root/assets/markdown-split-B_oc9lJe.js +1 -0
  54. package/dist/gateway/static/root/assets/media-plugins-DLPvB5H3.js +1 -0
  55. package/dist/gateway/static/root/assets/mermaid-render-BbqDc_LQ.js +134 -0
  56. package/dist/gateway/static/root/assets/messages-Csef1aW7.js +3 -0
  57. package/dist/gateway/static/root/assets/middleware-Pd0e8Igk.js +1 -0
  58. package/dist/gateway/static/root/assets/models-hub-panel-DHGiTIvf.js +2 -0
  59. package/dist/gateway/static/root/assets/note-detail-page-BM7zlDiT.js +2 -0
  60. package/dist/gateway/static/root/assets/note-image-lightbox-rSqAgOi9.js +1 -0
  61. package/dist/gateway/static/root/assets/note-time-hm6JO_Wi.js +1 -0
  62. package/dist/gateway/static/root/assets/notes-page-C9ACGEty.js +1 -0
  63. package/dist/gateway/static/root/assets/preview-open-alternatives-Bw_N2oZi.js +1 -0
  64. package/dist/gateway/static/root/assets/remote-access-hub-BhcWIKuM.js +1 -0
  65. package/dist/gateway/static/root/assets/save-bar-controls-CNP2jmw0.js +1 -0
  66. package/dist/gateway/static/root/assets/schedule-field-BPAWui3P.js +1 -0
  67. package/dist/gateway/static/root/assets/schedule-summary-B-hdSRdR.js +1 -0
  68. package/dist/gateway/static/root/assets/schema-form-CDPzua9q.js +1 -0
  69. package/dist/gateway/static/root/assets/sessions-page-DzkpSDZr.js +1 -0
  70. package/dist/gateway/static/root/assets/settings-advanced-gate-BYS-rpzn.js +1 -0
  71. package/dist/gateway/static/root/assets/settings-collapsible-section-C9bff85B.js +1 -0
  72. package/dist/gateway/static/root/assets/settings-form-section-BsrK7TBF.js +1 -0
  73. package/dist/gateway/static/root/assets/settings-page-DWK4Zo7s.js +1 -0
  74. package/dist/gateway/static/root/assets/setup-status-panel-DJiksNu4.js +1 -0
  75. package/dist/gateway/static/root/assets/share-preview-page-DnutoY_S.js +2 -0
  76. package/dist/gateway/static/root/assets/shares-settings-6oRgJMpn.js +1 -0
  77. package/dist/gateway/static/root/assets/skill-reload-api-CU9i0nJV.js +1 -0
  78. package/dist/gateway/static/root/assets/skills-page-ERbdWENm.js +2 -0
  79. package/dist/gateway/static/root/assets/system-settings-panel-qP1JDtDd.js +1 -0
  80. package/dist/gateway/static/root/assets/theme-store-CD2wtgZV.js +1 -0
  81. package/dist/gateway/static/root/assets/use-agent-defaults-form-D3FGVLZb.js +1 -0
  82. package/dist/gateway/static/root/assets/use-blob-object-url-D4BFuzZB.js +1 -0
  83. package/dist/gateway/static/root/assets/use-channel-catalog-C4mg1hjD.js +1 -0
  84. package/dist/gateway/static/root/assets/use-settings-tab-guard-F6C0mpJt.js +1 -0
  85. package/dist/gateway/static/root/assets/vendor-codemirror-CNP1wPe7.js +45 -0
  86. package/dist/gateway/static/root/assets/voice-api-key-field-BnDDb6qO.js +1 -0
  87. package/dist/gateway/static/root/assets/voice-player-store-B2EwIhtY.js +1 -0
  88. package/dist/gateway/static/root/assets/{workflow-page.utils-EYg_xBQS.js → workflow-page.utils-CRB7WX9l.js} +1 -1
  89. package/dist/gateway/static/root/assets/workflows-page-2Fptr0je.js +18 -0
  90. package/dist/gateway/static/root/index.html +12 -10
  91. package/dist/package.js +1 -1
  92. package/dist/src/agent/goals/checklist-judge.d.ts +5 -0
  93. package/dist/src/agent/goals/checklist-judge.js +26 -2
  94. package/dist/src/agent/goals/checklist-judge.js.map +1 -1
  95. package/dist/src/agent/goals/evaluate-turn.d.ts +5 -1
  96. package/dist/src/agent/goals/evaluate-turn.js +29 -3
  97. package/dist/src/agent/goals/evaluate-turn.js.map +1 -1
  98. package/dist/src/agent/goals/goal-locale.d.ts +0 -2
  99. package/dist/src/agent/goals/goal-locale.js +2 -15
  100. package/dist/src/agent/goals/goal-locale.js.map +1 -1
  101. package/dist/src/agent/goals/persistent-goal-service.d.ts +9 -0
  102. package/dist/src/agent/goals/persistent-goal-service.js +2 -1
  103. package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
  104. package/dist/src/agent/goals/post-turn.d.ts +7 -0
  105. package/dist/src/agent/goals/post-turn.js +68 -23
  106. package/dist/src/agent/goals/post-turn.js.map +1 -1
  107. package/dist/src/agent/goals/state.d.ts +0 -5
  108. package/dist/src/agent/goals/state.js +1 -96
  109. package/dist/src/agent/goals/state.js.map +1 -1
  110. package/dist/src/agent/messaging/command-handler.d.ts +4 -0
  111. package/dist/src/agent/messaging/command-handler.js +6 -2
  112. package/dist/src/agent/messaging/command-handler.js.map +1 -1
  113. package/dist/src/agent/service/direct-turn-helpers.d.ts +2 -0
  114. package/dist/src/agent/service/direct-turn-helpers.js +3 -2
  115. package/dist/src/agent/service/direct-turn-helpers.js.map +1 -1
  116. package/dist/src/agent/service/process-direct-streaming.js +10 -1
  117. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  118. package/dist/src/agent/service.js +20 -1
  119. package/dist/src/agent/service.js.map +1 -1
  120. package/dist/src/agent/service.types.d.ts +8 -0
  121. package/dist/src/agent/tools/cronjob-tool.d.ts +2 -0
  122. package/dist/src/agent/tools/cronjob-tool.js +27 -4
  123. package/dist/src/agent/tools/cronjob-tool.js.map +1 -1
  124. package/dist/src/agent/tools/edit.d.ts +2 -0
  125. package/dist/src/agent/tools/edit.js +10 -0
  126. package/dist/src/agent/tools/edit.js.map +1 -1
  127. package/dist/src/agent/tools/factory.js +16 -3
  128. package/dist/src/agent/tools/factory.js.map +1 -1
  129. package/dist/src/agent/tools/goal-evidence-recorder.d.ts +6 -0
  130. package/dist/src/agent/tools/goal-evidence-recorder.js +34 -0
  131. package/dist/src/agent/tools/goal-evidence-recorder.js.map +1 -0
  132. package/dist/src/agent/tools/goal-tool.d.ts +19 -0
  133. package/dist/src/agent/tools/goal-tool.js +101 -0
  134. package/dist/src/agent/tools/goal-tool.js.map +1 -0
  135. package/dist/src/agent/tools/index.d.ts +1 -0
  136. package/dist/src/agent/tools/index.js +2 -1
  137. package/dist/src/agent/tools/shell.d.ts +2 -0
  138. package/dist/src/agent/tools/shell.js +17 -2
  139. package/dist/src/agent/tools/shell.js.map +1 -1
  140. package/dist/src/agent/tools/workflow-tool.d.ts +1 -0
  141. package/dist/src/agent/tools/workflow-tool.js +10 -2
  142. package/dist/src/agent/tools/workflow-tool.js.map +1 -1
  143. package/dist/src/agent/tools/write.d.ts +2 -0
  144. package/dist/src/agent/tools/write.js +11 -0
  145. package/dist/src/agent/tools/write.js.map +1 -1
  146. package/dist/src/channels/attachments/inbound-persist.d.ts +7 -0
  147. package/dist/src/channels/attachments/inbound-persist.js +20 -2
  148. package/dist/src/channels/attachments/inbound-persist.js.map +1 -1
  149. package/dist/src/chat-commands/builtins/goal.d.ts +1 -1
  150. package/dist/src/chat-commands/builtins/goal.js +55 -97
  151. package/dist/src/chat-commands/builtins/goal.js.map +1 -1
  152. package/dist/src/chat-commands/builtins/subgoal.d.ts +1 -1
  153. package/dist/src/chat-commands/builtins/subgoal.js +49 -108
  154. package/dist/src/chat-commands/builtins/subgoal.js.map +1 -1
  155. package/dist/src/chat-commands/builtins/workflow.js +132 -8
  156. package/dist/src/chat-commands/builtins/workflow.js.map +1 -1
  157. package/dist/src/chat-commands/context.d.ts +3 -0
  158. package/dist/src/chat-commands/context.js +5 -0
  159. package/dist/src/chat-commands/context.js.map +1 -1
  160. package/dist/src/chat-commands/types.d.ts +5 -0
  161. package/dist/src/cli/command-catalog.js +43 -0
  162. package/dist/src/cli/command-catalog.js.map +1 -1
  163. package/dist/src/cli/command-loaders.js +1 -0
  164. package/dist/src/cli/command-loaders.js.map +1 -1
  165. package/dist/src/cli/command-manifest.js +4 -0
  166. package/dist/src/cli/command-manifest.js.map +1 -1
  167. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  168. package/dist/src/cli/commands/goal.d.ts +4 -0
  169. package/dist/src/cli/commands/goal.js +213 -0
  170. package/dist/src/cli/commands/goal.js.map +1 -0
  171. package/dist/src/cli/commands/onboard.js +11 -5
  172. package/dist/src/cli/commands/onboard.js.map +1 -1
  173. package/dist/src/config/index.js +2 -2
  174. package/dist/src/config/schema.d.ts +115 -0
  175. package/dist/src/config/schema.js +63 -4
  176. package/dist/src/config/schema.js.map +1 -1
  177. package/dist/src/config/web-patch.d.ts +14 -0
  178. package/dist/src/config/web-patch.js +45 -6
  179. package/dist/src/config/web-patch.js.map +1 -1
  180. package/dist/src/cron/executor.d.ts +2 -0
  181. package/dist/src/cron/executor.js +25 -0
  182. package/dist/src/cron/executor.js.map +1 -1
  183. package/dist/src/cron/job-content.js +1 -0
  184. package/dist/src/cron/job-content.js.map +1 -1
  185. package/dist/src/cron/types.d.ts +19 -1
  186. package/dist/src/cron/validation.d.ts +20 -0
  187. package/dist/src/cron/validation.js +7 -0
  188. package/dist/src/cron/validation.js.map +1 -1
  189. package/dist/src/gateway/hono/lib/config-payload.d.ts +14 -0
  190. package/dist/src/gateway/hono/routes/goals.d.ts +1 -1
  191. package/dist/src/gateway/hono/routes/goals.js +670 -173
  192. package/dist/src/gateway/hono/routes/goals.js.map +1 -1
  193. package/dist/src/gateway/hono/routes/home.d.ts +5 -0
  194. package/dist/src/gateway/hono/routes/home.js +88 -3
  195. package/dist/src/gateway/hono/routes/home.js.map +1 -1
  196. package/dist/src/gateway/hono/routes/notes.js +20 -14
  197. package/dist/src/gateway/hono/routes/notes.js.map +1 -1
  198. package/dist/src/gateway/hono/routes/workflows.js +6 -2
  199. package/dist/src/gateway/hono/routes/workflows.js.map +1 -1
  200. package/dist/src/gateway/hono/sse.js.map +1 -1
  201. package/dist/src/gateway/service/agent-runner.d.ts +2 -0
  202. package/dist/src/gateway/service/agent-runner.js +6 -2
  203. package/dist/src/gateway/service/agent-runner.js.map +1 -1
  204. package/dist/src/gateway/service/run-gateway-agent.d.ts +3 -0
  205. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  206. package/dist/src/gateway/service.d.ts +8 -0
  207. package/dist/src/gateway/service.js +69 -2
  208. package/dist/src/gateway/service.js.map +1 -1
  209. package/dist/src/goals/goal-notifications.d.ts +29 -0
  210. package/dist/src/goals/goal-notifications.js +154 -0
  211. package/dist/src/goals/goal-notifications.js.map +1 -0
  212. package/dist/src/goals/goal-queue-store.d.ts +16 -0
  213. package/dist/src/goals/goal-queue-store.js +131 -0
  214. package/dist/src/goals/goal-queue-store.js.map +1 -0
  215. package/dist/src/goals/goal-queue-types.d.ts +31 -0
  216. package/dist/src/goals/goal-queue-types.js +1 -0
  217. package/dist/src/goals/goal-runner.d.ts +17 -0
  218. package/dist/src/goals/goal-runner.js +127 -0
  219. package/dist/src/goals/goal-runner.js.map +1 -0
  220. package/dist/src/goals/goal-service.d.ts +77 -0
  221. package/dist/src/goals/goal-service.js +261 -0
  222. package/dist/src/goals/goal-service.js.map +1 -0
  223. package/dist/src/goals/goal-store.d.ts +38 -0
  224. package/dist/src/goals/goal-store.js +404 -0
  225. package/dist/src/goals/goal-store.js.map +1 -0
  226. package/dist/src/goals/goal-workflow-judge.d.ts +13 -0
  227. package/dist/src/goals/goal-workflow-judge.js +147 -0
  228. package/dist/src/goals/goal-workflow-judge.js.map +1 -0
  229. package/dist/src/goals/index.d.ts +10 -0
  230. package/dist/src/goals/index.js +7 -0
  231. package/dist/src/goals/types.d.ts +119 -0
  232. package/dist/src/goals/types.js +1 -0
  233. package/dist/src/storage/sqlite/migrations/006_add_goals.sql +108 -0
  234. package/dist/src/storage/sqlite/migrations/007_goal_run_judge_schema.sql +4 -0
  235. package/dist/src/storage/sqlite/migrations/008_goal_queue_workflow_runs.sql +53 -0
  236. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  237. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  238. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  239. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  240. package/dist/src/storage/sqlite/schema.js +1 -1
  241. package/dist/src/storage/sqlite/schema.sql +163 -0
  242. package/dist/src/utils/logger/stats.d.ts +1 -1
  243. package/dist/src/workflows/domain/run.d.ts +1 -0
  244. package/dist/src/workflows/domain/run.js.map +1 -1
  245. package/dist/src/workflows/service/workflow-run-service.d.ts +1 -0
  246. package/dist/src/workflows/service/workflow-run-service.js +5 -1
  247. package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
  248. package/dist/src/workflows/service/workflow-run-service.types.d.ts +1 -0
  249. package/dist/src/workflows/service/workflow-session-bridge.js +7 -0
  250. package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
  251. package/dist/src/workflows/store/run-index-store.d.ts +8 -0
  252. package/dist/src/workflows/store/run-index-store.js +58 -0
  253. package/dist/src/workflows/store/run-index-store.js.map +1 -0
  254. package/dist/src/workflows/store/run-store.d.ts +2 -0
  255. package/dist/src/workflows/store/run-store.js +14 -21
  256. package/dist/src/workflows/store/run-store.js.map +1 -1
  257. package/package.json +9 -3
  258. package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +0 -41
  259. package/dist/gateway/static/root/assets/agents-CFFioJCI.js +0 -78
  260. package/dist/gateway/static/root/assets/apps-page-BYDmkbzG.js +0 -1
  261. package/dist/gateway/static/root/assets/channels-settings-CsbDaMvd.js +0 -1
  262. package/dist/gateway/static/root/assets/circle-check-C23XjkUj.js +0 -1
  263. package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +0 -1
  264. package/dist/gateway/static/root/assets/cron-page-Apk-7p4p.js +0 -1
  265. package/dist/gateway/static/root/assets/dist-DmGDgpy2.js +0 -1
  266. package/dist/gateway/static/root/assets/extension-debug-page-pxFC-tUa.js +0 -1
  267. package/dist/gateway/static/root/assets/extension-settings-page-COXSv6xP.js +0 -1
  268. package/dist/gateway/static/root/assets/fetch-CFdKBnE6.js +0 -1
  269. package/dist/gateway/static/root/assets/gateway-startup-retry-DdngdObI.js +0 -1
  270. package/dist/gateway/static/root/assets/heartbeat-config-api-DcmAMYmN.js +0 -1
  271. package/dist/gateway/static/root/assets/index-C_2yKRJX.js +0 -4845
  272. package/dist/gateway/static/root/assets/index-DI5_GsZt.css +0 -1
  273. package/dist/gateway/static/root/assets/logs-page-DvTWUOzd.js +0 -2
  274. package/dist/gateway/static/root/assets/note-detail-page-CZbdugWZ.js +0 -180
  275. package/dist/gateway/static/root/assets/note-time-RdyBZxj3.js +0 -1
  276. package/dist/gateway/static/root/assets/notes-page-mEAwy3e1.js +0 -1
  277. package/dist/gateway/static/root/assets/schema-form-DEvdni_r.js +0 -1
  278. package/dist/gateway/static/root/assets/sessions-page-BsgffzV4.js +0 -1
  279. package/dist/gateway/static/root/assets/settings-advanced-gate-t6v8Dwb8.js +0 -2
  280. package/dist/gateway/static/root/assets/settings-form-section-BoYYZmJG.js +0 -1
  281. package/dist/gateway/static/root/assets/settings-page-ClIthYF8.js +0 -3
  282. package/dist/gateway/static/root/assets/share-preview-page-Dd9et7KD.js +0 -2
  283. package/dist/gateway/static/root/assets/skills-page-DEXtxyfQ.js +0 -2
  284. package/dist/gateway/static/root/assets/theme-store-BZozwAeK.js +0 -1
  285. package/dist/gateway/static/root/assets/url-DQRqHuL-.js +0 -3
  286. package/dist/gateway/static/root/assets/vendor-codemirror-DYoKfS8f.js +0 -45
  287. package/dist/gateway/static/root/assets/voice-api-key-field-CNrKzQrf.js +0 -1
  288. package/dist/gateway/static/root/assets/workflows-page-EMZkzJNN.js +0 -18
  289. package/dist/src/agent/goals/checklist-user.d.ts +0 -24
  290. package/dist/src/agent/goals/checklist-user.js +0 -92
  291. package/dist/src/agent/goals/checklist-user.js.map +0 -1
  292. package/dist/src/agent/goals/goal-run-store.d.ts +0 -19
  293. package/dist/src/agent/goals/goal-run-store.js +0 -138
  294. package/dist/src/agent/goals/goal-run-store.js.map +0 -1
  295. package/dist/src/agent/goals/goal-run-types.d.ts +0 -28
  296. package/dist/src/agent/goals/goal-run-types.js +0 -6
  297. package/dist/src/agent/goals/goal-run-types.js.map +0 -1
  298. package/dist/src/agent/goals/patch-from-user-action.d.ts +0 -20
  299. package/dist/src/agent/goals/patch-from-user-action.js +0 -103
  300. package/dist/src/agent/goals/patch-from-user-action.js.map +0 -1
  301. /package/dist/gateway/static/root/assets/{note-detail-page-D4ZIVQbk.css → block-editor-D4ZIVQbk.css} +0 -0
@@ -118,6 +118,8 @@ async function evaluateAfterTurnHermesLike(state, lastResponse, judgeModelRef, s
118
118
  }
119
119
  next.lastVerdict = "continue";
120
120
  next.lastReason = evalResult.parsed.reason;
121
+ const completedChecklistItemIndexes = evalResult.parsed.updates.filter((update) => update.status === "completed" || update.status === "impossible").map((update) => update.index);
122
+ const continuationPrompt = evalResult.parsed.nextAction?.trim() || buildContinuationPromptFromState(next, locale);
121
123
  if (!evalResult.parseFailed && allChecklistTerminal(next.checklist ?? [])) {
122
124
  next.status = "done";
123
125
  next.lastVerdict = "done";
@@ -127,7 +129,27 @@ async function evaluateAfterTurnHermesLike(state, lastResponse, judgeModelRef, s
127
129
  continuationPrompt: null,
128
130
  verdict: "done",
129
131
  reason: evalResult.parsed.reason,
130
- message: copy.goalAchieved(evalResult.parsed.reason)
132
+ message: copy.goalAchieved(evalResult.parsed.reason),
133
+ confidence: evalResult.parsed.confidence,
134
+ missingEvidence: evalResult.parsed.missingEvidence,
135
+ userQuestion: evalResult.parsed.userQuestion,
136
+ completedChecklistItemIndexes
137
+ };
138
+ }
139
+ if (!evalResult.parseFailed && (evalResult.parsed.verdict === "blocked" || evalResult.parsed.verdict === "needs_input")) {
140
+ next.status = "paused";
141
+ next.pausedReason = evalResult.parsed.reason;
142
+ return {
143
+ newState: next,
144
+ shouldContinue: false,
145
+ continuationPrompt: null,
146
+ verdict: evalResult.parsed.verdict,
147
+ reason: evalResult.parsed.reason,
148
+ message: evalResult.parsed.verdict === "needs_input" ? `Goal needs input: ${evalResult.parsed.userQuestion || evalResult.parsed.reason}` : `Goal blocked: ${evalResult.parsed.reason}`,
149
+ confidence: evalResult.parsed.confidence,
150
+ missingEvidence: evalResult.parsed.missingEvidence,
151
+ userQuestion: evalResult.parsed.userQuestion,
152
+ completedChecklistItemIndexes
131
153
  };
132
154
  }
133
155
  const parseStorm = pauseIfParseStorm(evalResult.parsed.reason);
@@ -139,10 +161,14 @@ async function evaluateAfterTurnHermesLike(state, lastResponse, judgeModelRef, s
139
161
  return {
140
162
  newState: next,
141
163
  shouldContinue: true,
142
- continuationPrompt: buildContinuationPromptFromState(next, locale),
164
+ continuationPrompt,
143
165
  verdict: "continue",
144
166
  reason: evalResult.parsed.reason,
145
- message: copy.continuingWithProgress(next.turnsUsed, next.maxTurns, progressSuffix, evalResult.parsed.reason)
167
+ message: copy.continuingWithProgress(next.turnsUsed, next.maxTurns, progressSuffix, evalResult.parsed.reason),
168
+ confidence: evalResult.parsed.confidence,
169
+ missingEvidence: evalResult.parsed.missingEvidence,
170
+ userQuestion: evalResult.parsed.userQuestion,
171
+ completedChecklistItemIndexes
146
172
  };
147
173
  }
148
174
  const j = await judgeGoalHermesStyle(state.goal, lastResponse, judgeModelRef, signal, {
@@ -1 +1 @@
1
- {"version":3,"file":"evaluate-turn.js","names":[],"sources":["../../../../src/agent/goals/evaluate-turn.ts"],"sourcesContent":["import type { GoalsConfig } from '../../config/schema.js';\n\nimport { decomposeGoalChecklist, evaluateGoalChecklistJudge } from './checklist-judge.js';\nimport { allChecklistTerminal, checklistCounts } from './checklist-types.js';\nimport {\n buildContinuationPromptFromState,\n checklistProgressSuffix,\n CONTINUATION_PROMPT_TEMPLATE_EN,\n CONTINUATION_PROMPT_WITH_CHECKLIST_TEMPLATE_EN,\n goalEvaluateUserCopy,\n resolveGoalUiLocale,\n type GoalUiLocale,\n} from './goal-locale.js';\nimport { judgeGoalHermesStyle } from './judge.js';\nimport {\n applyJudgeChecklistUpdates,\n mergeDecomposedChecklistItems,\n renderChecklistNumbered,\n type PersistentGoalState,\n} from './state.js';\n\n/** Hermes `CONTINUATION_PROMPT_TEMPLATE` (English; parity / tests). */\nexport const CONTINUATION_PROMPT_TEMPLATE = CONTINUATION_PROMPT_TEMPLATE_EN;\n\n/** Hermes `CONTINUATION_PROMPT_WITH_CHECKLIST_TEMPLATE` (English; parity / tests). */\nexport const CONTINUATION_PROMPT_WITH_CHECKLIST_TEMPLATE = CONTINUATION_PROMPT_WITH_CHECKLIST_TEMPLATE_EN;\n\nexport type GoalsEvaluateConfigSlice = Pick<\n GoalsConfig,\n 'checklistMode' | 'maxConsecutiveParseFailures' | 'judgeTimeoutMs' | 'checklistHistoryChars'\n>;\n\nexport type GoalPostTurnDecision = {\n newState: PersistentGoalState | null;\n shouldContinue: boolean;\n continuationPrompt: string | null;\n verdict: 'done' | 'continue' | 'skipped' | 'inactive' | 'decompose';\n reason: string;\n message: string;\n};\n\nfunction cloneState(s: PersistentGoalState): PersistentGoalState {\n return {\n ...s,\n checklist: s.checklist?.map((it) => ({ ...it })),\n };\n}\n\n/**\n * Hermes `GoalManager.evaluate_after_turn` equivalent (minus SessionDB I/O).\n */\nexport async function evaluateAfterTurnHermesLike(\n state: PersistentGoalState,\n lastResponse: string,\n judgeModelRef: string,\n signal?: AbortSignal,\n opts?: { goalsSlice?: Partial<GoalsEvaluateConfigSlice>; historyExcerpt?: string; uiLocale?: GoalUiLocale },\n): Promise<GoalPostTurnDecision> {\n const locale = opts?.uiLocale ?? resolveGoalUiLocale(state);\n const copy = goalEvaluateUserCopy(locale);\n\n if (state.status !== 'active') {\n return {\n newState: state,\n shouldContinue: false,\n continuationPrompt: null,\n verdict: 'inactive',\n reason: 'no active goal',\n message: '',\n };\n }\n\n const slice = opts?.goalsSlice;\n const checklistMode = slice?.checklistMode !== false;\n const maxParseFailures = slice?.maxConsecutiveParseFailures ?? 3;\n const judgeTimeoutMs = slice?.judgeTimeoutMs;\n\n const next = cloneState(state);\n next.turnsUsed += 1;\n next.lastTurnAt = Date.now();\n\n const bumpParse = () => {\n next.consecutiveParseFailures = (next.consecutiveParseFailures ?? 0) + 1;\n };\n const resetParse = () => {\n next.consecutiveParseFailures = 0;\n };\n\n const pauseIfParseStorm = (reason: string): GoalPostTurnDecision | null => {\n const n = next.consecutiveParseFailures ?? 0;\n if (n < maxParseFailures) return null;\n next.status = 'paused';\n next.pausedReason = `judge parse failures (${n} consecutive)`;\n return {\n newState: next,\n shouldContinue: false,\n continuationPrompt: null,\n verdict: 'continue',\n reason,\n message: copy.pauseParse(n),\n };\n };\n\n const pauseIfBudget = (reason: string): GoalPostTurnDecision | null => {\n if (next.turnsUsed < next.maxTurns) return null;\n next.status = 'paused';\n next.pausedReason = `turn budget exhausted (${next.turnsUsed}/${next.maxTurns})`;\n return {\n newState: next,\n shouldContinue: false,\n continuationPrompt: null,\n verdict: 'continue',\n reason,\n message: copy.pauseBudget(next.turnsUsed, next.maxTurns),\n };\n };\n\n // ── Phase A: decompose (once per goal when checklist mode is on) ──\n if (checklistMode && !next.decomposed) {\n const dec = await decomposeGoalChecklist({\n goal: next.goal,\n judgeModelRef,\n signal,\n judgeTimeoutMs,\n uiLocale: locale,\n });\n next.decomposed = true;\n if (!dec.parseFailed && dec.items.length > 0) {\n const prior = next.checklist ?? [];\n next.checklist = mergeDecomposedChecklistItems(prior, dec.items);\n const mergedCount = next.checklist.length;\n next.lastVerdict = 'decompose';\n next.lastReason = copy.decomposedReason(mergedCount);\n resetParse();\n const budgetEarly = pauseIfBudget(next.lastReason);\n if (budgetEarly) return budgetEarly;\n return {\n newState: next,\n shouldContinue: true,\n continuationPrompt: buildContinuationPromptFromState(next, locale),\n verdict: 'decompose',\n reason: next.lastReason ?? '',\n message: copy.checklistReady(mergedCount),\n };\n }\n next.lastReason = dec.errorReason\n ? copy.decomposeFallbackReason(dec.errorReason)\n : copy.noChecklistFallback();\n }\n\n // ── Phase B: checklist judge ──\n const checklist = next.checklist ?? [];\n if (checklist.length > 0) {\n const evalResult = await evaluateGoalChecklistJudge({\n goal: next.goal,\n numberedChecklist: renderChecklistNumbered(checklist),\n lastResponse,\n historyExcerpt: opts?.historyExcerpt ?? '',\n judgeModelRef,\n signal,\n judgeTimeoutMs,\n uiLocale: locale,\n });\n\n if (evalResult.parseFailed) {\n bumpParse();\n } else {\n resetParse();\n next.checklist = applyJudgeChecklistUpdates(checklist, {\n updates: evalResult.parsed.updates,\n newItems: evalResult.parsed.newItems,\n });\n }\n\n next.lastVerdict = 'continue';\n next.lastReason = evalResult.parsed.reason;\n\n if (!evalResult.parseFailed && allChecklistTerminal(next.checklist ?? [])) {\n next.status = 'done';\n next.lastVerdict = 'done';\n return {\n newState: next,\n shouldContinue: false,\n continuationPrompt: null,\n verdict: 'done',\n reason: evalResult.parsed.reason,\n message: copy.goalAchieved(evalResult.parsed.reason),\n };\n }\n\n const parseStorm = pauseIfParseStorm(evalResult.parsed.reason);\n if (parseStorm) return parseStorm;\n\n const budget = pauseIfBudget(evalResult.parsed.reason);\n if (budget) return budget;\n\n const { total, completed, impossible } = checklistCounts(next.checklist ?? []);\n const done = completed + impossible;\n const progressSuffix = checklistProgressSuffix(done, total, locale);\n\n return {\n newState: next,\n shouldContinue: true,\n continuationPrompt: buildContinuationPromptFromState(next, locale),\n verdict: 'continue',\n reason: evalResult.parsed.reason,\n message: copy.continuingWithProgress(\n next.turnsUsed,\n next.maxTurns,\n progressSuffix,\n evalResult.parsed.reason,\n ),\n };\n }\n\n // ── Freeform judge (no checklist) ──\n const j = await judgeGoalHermesStyle(state.goal, lastResponse, judgeModelRef, signal, {\n judgeTimeoutMs,\n uiLocale: locale,\n });\n next.lastVerdict = j.verdict === 'skipped' ? 'skipped' : j.verdict;\n next.lastReason = j.reason;\n\n if (j.parseFailed) bumpParse();\n else resetParse();\n\n if (j.verdict === 'done') {\n next.status = 'done';\n return {\n newState: next,\n shouldContinue: false,\n continuationPrompt: null,\n verdict: 'done',\n reason: j.reason,\n message: copy.goalAchieved(j.reason),\n };\n }\n\n const parseStorm = pauseIfParseStorm(j.reason);\n if (parseStorm) return parseStorm;\n\n const budget = pauseIfBudget(j.reason);\n if (budget) return budget;\n\n return {\n newState: next,\n shouldContinue: true,\n continuationPrompt: buildContinuationPromptFromState(next, locale),\n verdict: 'continue',\n reason: j.reason,\n message: copy.continuing(next.turnsUsed, next.maxTurns, j.reason),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"evaluate-turn.js","names":[],"sources":["../../../../src/agent/goals/evaluate-turn.ts"],"sourcesContent":["import type { GoalsConfig } from '../../config/schema.js';\n\nimport { decomposeGoalChecklist, evaluateGoalChecklistJudge } from './checklist-judge.js';\nimport { allChecklistTerminal, checklistCounts } from './checklist-types.js';\nimport {\n buildContinuationPromptFromState,\n checklistProgressSuffix,\n CONTINUATION_PROMPT_TEMPLATE_EN,\n CONTINUATION_PROMPT_WITH_CHECKLIST_TEMPLATE_EN,\n goalEvaluateUserCopy,\n resolveGoalUiLocale,\n type GoalUiLocale,\n} from './goal-locale.js';\nimport { judgeGoalHermesStyle } from './judge.js';\nimport {\n applyJudgeChecklistUpdates,\n mergeDecomposedChecklistItems,\n renderChecklistNumbered,\n type PersistentGoalState,\n} from './state.js';\n\n/** Hermes `CONTINUATION_PROMPT_TEMPLATE` (English; parity / tests). */\nexport const CONTINUATION_PROMPT_TEMPLATE = CONTINUATION_PROMPT_TEMPLATE_EN;\n\n/** Hermes `CONTINUATION_PROMPT_WITH_CHECKLIST_TEMPLATE` (English; parity / tests). */\nexport const CONTINUATION_PROMPT_WITH_CHECKLIST_TEMPLATE = CONTINUATION_PROMPT_WITH_CHECKLIST_TEMPLATE_EN;\n\nexport type GoalsEvaluateConfigSlice = Pick<\n GoalsConfig,\n 'checklistMode' | 'maxConsecutiveParseFailures' | 'judgeTimeoutMs' | 'checklistHistoryChars'\n>;\n\nexport type GoalPostTurnDecision = {\n newState: PersistentGoalState | null;\n shouldContinue: boolean;\n continuationPrompt: string | null;\n verdict: 'done' | 'continue' | 'blocked' | 'needs_input' | 'skipped' | 'inactive' | 'decompose';\n reason: string;\n message: string;\n confidence?: number;\n missingEvidence?: string[];\n userQuestion?: string;\n completedChecklistItemIndexes?: number[];\n};\n\nfunction cloneState(s: PersistentGoalState): PersistentGoalState {\n return {\n ...s,\n checklist: s.checklist?.map((it) => ({ ...it })),\n };\n}\n\n/**\n * Hermes `GoalManager.evaluate_after_turn` equivalent (minus SessionDB I/O).\n */\nexport async function evaluateAfterTurnHermesLike(\n state: PersistentGoalState,\n lastResponse: string,\n judgeModelRef: string,\n signal?: AbortSignal,\n opts?: { goalsSlice?: Partial<GoalsEvaluateConfigSlice>; historyExcerpt?: string; uiLocale?: GoalUiLocale },\n): Promise<GoalPostTurnDecision> {\n const locale = opts?.uiLocale ?? resolveGoalUiLocale(state);\n const copy = goalEvaluateUserCopy(locale);\n\n if (state.status !== 'active') {\n return {\n newState: state,\n shouldContinue: false,\n continuationPrompt: null,\n verdict: 'inactive',\n reason: 'no active goal',\n message: '',\n };\n }\n\n const slice = opts?.goalsSlice;\n const checklistMode = slice?.checklistMode !== false;\n const maxParseFailures = slice?.maxConsecutiveParseFailures ?? 3;\n const judgeTimeoutMs = slice?.judgeTimeoutMs;\n\n const next = cloneState(state);\n next.turnsUsed += 1;\n next.lastTurnAt = Date.now();\n\n const bumpParse = () => {\n next.consecutiveParseFailures = (next.consecutiveParseFailures ?? 0) + 1;\n };\n const resetParse = () => {\n next.consecutiveParseFailures = 0;\n };\n\n const pauseIfParseStorm = (reason: string): GoalPostTurnDecision | null => {\n const n = next.consecutiveParseFailures ?? 0;\n if (n < maxParseFailures) return null;\n next.status = 'paused';\n next.pausedReason = `judge parse failures (${n} consecutive)`;\n return {\n newState: next,\n shouldContinue: false,\n continuationPrompt: null,\n verdict: 'continue',\n reason,\n message: copy.pauseParse(n),\n };\n };\n\n const pauseIfBudget = (reason: string): GoalPostTurnDecision | null => {\n if (next.turnsUsed < next.maxTurns) return null;\n next.status = 'paused';\n next.pausedReason = `turn budget exhausted (${next.turnsUsed}/${next.maxTurns})`;\n return {\n newState: next,\n shouldContinue: false,\n continuationPrompt: null,\n verdict: 'continue',\n reason,\n message: copy.pauseBudget(next.turnsUsed, next.maxTurns),\n };\n };\n\n // ── Phase A: decompose (once per goal when checklist mode is on) ──\n if (checklistMode && !next.decomposed) {\n const dec = await decomposeGoalChecklist({\n goal: next.goal,\n judgeModelRef,\n signal,\n judgeTimeoutMs,\n uiLocale: locale,\n });\n next.decomposed = true;\n if (!dec.parseFailed && dec.items.length > 0) {\n const prior = next.checklist ?? [];\n next.checklist = mergeDecomposedChecklistItems(prior, dec.items);\n const mergedCount = next.checklist.length;\n next.lastVerdict = 'decompose';\n next.lastReason = copy.decomposedReason(mergedCount);\n resetParse();\n const budgetEarly = pauseIfBudget(next.lastReason);\n if (budgetEarly) return budgetEarly;\n return {\n newState: next,\n shouldContinue: true,\n continuationPrompt: buildContinuationPromptFromState(next, locale),\n verdict: 'decompose',\n reason: next.lastReason ?? '',\n message: copy.checklistReady(mergedCount),\n };\n }\n next.lastReason = dec.errorReason\n ? copy.decomposeFallbackReason(dec.errorReason)\n : copy.noChecklistFallback();\n }\n\n // ── Phase B: checklist judge ──\n const checklist = next.checklist ?? [];\n if (checklist.length > 0) {\n const evalResult = await evaluateGoalChecklistJudge({\n goal: next.goal,\n numberedChecklist: renderChecklistNumbered(checklist),\n lastResponse,\n historyExcerpt: opts?.historyExcerpt ?? '',\n judgeModelRef,\n signal,\n judgeTimeoutMs,\n uiLocale: locale,\n });\n\n if (evalResult.parseFailed) {\n bumpParse();\n } else {\n resetParse();\n next.checklist = applyJudgeChecklistUpdates(checklist, {\n updates: evalResult.parsed.updates,\n newItems: evalResult.parsed.newItems,\n });\n }\n\n next.lastVerdict = 'continue';\n next.lastReason = evalResult.parsed.reason;\n\n const completedChecklistItemIndexes = evalResult.parsed.updates\n .filter((update) => update.status === 'completed' || update.status === 'impossible')\n .map((update) => update.index);\n const structuredNextAction = evalResult.parsed.nextAction?.trim();\n const continuationPrompt = structuredNextAction || buildContinuationPromptFromState(next, locale);\n\n if (!evalResult.parseFailed && allChecklistTerminal(next.checklist ?? [])) {\n next.status = 'done';\n next.lastVerdict = 'done';\n return {\n newState: next,\n shouldContinue: false,\n continuationPrompt: null,\n verdict: 'done',\n reason: evalResult.parsed.reason,\n message: copy.goalAchieved(evalResult.parsed.reason),\n confidence: evalResult.parsed.confidence,\n missingEvidence: evalResult.parsed.missingEvidence,\n userQuestion: evalResult.parsed.userQuestion,\n completedChecklistItemIndexes,\n };\n }\n\n if (!evalResult.parseFailed && (evalResult.parsed.verdict === 'blocked' || evalResult.parsed.verdict === 'needs_input')) {\n next.status = 'paused';\n next.pausedReason = evalResult.parsed.reason;\n return {\n newState: next,\n shouldContinue: false,\n continuationPrompt: null,\n verdict: evalResult.parsed.verdict,\n reason: evalResult.parsed.reason,\n message: evalResult.parsed.verdict === 'needs_input'\n ? `Goal needs input: ${evalResult.parsed.userQuestion || evalResult.parsed.reason}`\n : `Goal blocked: ${evalResult.parsed.reason}`,\n confidence: evalResult.parsed.confidence,\n missingEvidence: evalResult.parsed.missingEvidence,\n userQuestion: evalResult.parsed.userQuestion,\n completedChecklistItemIndexes,\n };\n }\n\n const parseStorm = pauseIfParseStorm(evalResult.parsed.reason);\n if (parseStorm) return parseStorm;\n\n const budget = pauseIfBudget(evalResult.parsed.reason);\n if (budget) return budget;\n\n const { total, completed, impossible } = checklistCounts(next.checklist ?? []);\n const done = completed + impossible;\n const progressSuffix = checklistProgressSuffix(done, total, locale);\n\n return {\n newState: next,\n shouldContinue: true,\n continuationPrompt,\n verdict: 'continue',\n reason: evalResult.parsed.reason,\n message: copy.continuingWithProgress(\n next.turnsUsed,\n next.maxTurns,\n progressSuffix,\n evalResult.parsed.reason,\n ),\n confidence: evalResult.parsed.confidence,\n missingEvidence: evalResult.parsed.missingEvidence,\n userQuestion: evalResult.parsed.userQuestion,\n completedChecklistItemIndexes,\n };\n }\n\n // ── Freeform judge (no checklist) ──\n const j = await judgeGoalHermesStyle(state.goal, lastResponse, judgeModelRef, signal, {\n judgeTimeoutMs,\n uiLocale: locale,\n });\n next.lastVerdict = j.verdict === 'skipped' ? 'skipped' : j.verdict;\n next.lastReason = j.reason;\n\n if (j.parseFailed) bumpParse();\n else resetParse();\n\n if (j.verdict === 'done') {\n next.status = 'done';\n return {\n newState: next,\n shouldContinue: false,\n continuationPrompt: null,\n verdict: 'done',\n reason: j.reason,\n message: copy.goalAchieved(j.reason),\n };\n }\n\n const parseStorm = pauseIfParseStorm(j.reason);\n if (parseStorm) return parseStorm;\n\n const budget = pauseIfBudget(j.reason);\n if (budget) return budget;\n\n return {\n newState: next,\n shouldContinue: true,\n continuationPrompt: buildContinuationPromptFromState(next, locale),\n verdict: 'continue',\n reason: j.reason,\n message: copy.continuing(next.turnsUsed, next.maxTurns, j.reason),\n };\n}\n"],"mappings":"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"}
@@ -24,5 +24,3 @@ export declare function judgeFreeformBuiltinMessages(locale: GoalUiLocale): {
24
24
  export declare function checklistProgressSuffix(done: number, total: number, locale: GoalUiLocale): string;
25
25
  export type GoalEvaluateUserCopyPack = ReturnType<typeof goalsEvaluateCopy>;
26
26
  export declare function goalEvaluateUserCopy(locale: GoalUiLocale): GoalEvaluateUserCopyPack;
27
- /** Persist `uiLocale` on the standing goal when the gateway console language is known. */
28
- export declare function mergePersistentGoalUiLocale(customData: Record<string, unknown> | undefined, locale: GoalUiLocale | undefined): Record<string, unknown> | undefined;
@@ -1,7 +1,7 @@
1
1
  import { formatI18n } from "../../i18n/format.js";
2
2
  import { SERVER_LOCALES, isServerLocale, normalizeServerLocale, serverLocaleOrFallback } from "../../i18n/locale.js";
3
3
  import { checklistCounts } from "./checklist-types.js";
4
- import { PERSISTENT_GOAL_CUSTOM_KEY, mergeCustomDataPatch, readPersistentGoal, renderChecklistPlain, serializePersistentGoal } from "./state.js";
4
+ import { renderChecklistPlain } from "./state.js";
5
5
  import { JUDGE_REASON_EN, goalsChecklistProgressSuffix, goalsContinuationChecklistTemplate, goalsContinuationPlainTemplate, goalsEvaluateCopy, goalsJudgeReason, goalsJudgeResponseLanguageNote } from "../../i18n/goals-bundle.js";
6
6
  //#region src/agent/goals/goal-locale.ts
7
7
  const GOAL_UI_LOCALES = SERVER_LOCALES;
@@ -57,20 +57,7 @@ function checklistProgressSuffix(done, total, locale) {
57
57
  function goalEvaluateUserCopy(locale) {
58
58
  return goalsEvaluateCopy(goalUiLocaleOrFallback(locale));
59
59
  }
60
- /** Persist `uiLocale` on the standing goal when the gateway console language is known. */
61
- function mergePersistentGoalUiLocale(customData, locale) {
62
- if (!locale) return customData;
63
- const canonical = goalUiLocaleOrFallback(locale);
64
- const g = readPersistentGoal(customData);
65
- if (!g || g.status === "cleared") return customData;
66
- if (g.uiLocale === canonical) return customData;
67
- const next = {
68
- ...g,
69
- uiLocale: canonical
70
- };
71
- return mergeCustomDataPatch(customData ?? {}, { [PERSISTENT_GOAL_CUSTOM_KEY]: serializePersistentGoal(next) });
72
- }
73
60
  //#endregion
74
- export { CONTINUATION_PROMPT_TEMPLATE_EN, CONTINUATION_PROMPT_WITH_CHECKLIST_TEMPLATE_EN, DEFAULT_GOAL_UI_LOCALE, GOAL_UI_LOCALES, JUDGE_REASON_EN, buildContinuationPromptFromState, checklistProgressSuffix, goalEvaluateUserCopy, goalUiLocaleOrFallback, isGoalUiLocale, judgeFreeformBuiltinMessages, judgeReasonText, judgeResponseLanguageNote, localizeJudgeReasonText, mergePersistentGoalUiLocale, normalizeGoalUiLocale, resolveGoalUiLocale };
61
+ export { CONTINUATION_PROMPT_TEMPLATE_EN, CONTINUATION_PROMPT_WITH_CHECKLIST_TEMPLATE_EN, DEFAULT_GOAL_UI_LOCALE, GOAL_UI_LOCALES, JUDGE_REASON_EN, buildContinuationPromptFromState, checklistProgressSuffix, goalEvaluateUserCopy, goalUiLocaleOrFallback, isGoalUiLocale, judgeFreeformBuiltinMessages, judgeReasonText, judgeResponseLanguageNote, localizeJudgeReasonText, normalizeGoalUiLocale, resolveGoalUiLocale };
75
62
 
76
63
  //# sourceMappingURL=goal-locale.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"goal-locale.js","names":[],"sources":["../../../../src/agent/goals/goal-locale.ts"],"sourcesContent":["import { checklistCounts } from './checklist-types.js';\nimport {\n mergeCustomDataPatch,\n PERSISTENT_GOAL_CUSTOM_KEY,\n readPersistentGoal,\n renderChecklistPlain,\n serializePersistentGoal,\n type PersistentGoalState,\n} from './state.js';\n\nimport { formatI18n } from '../../i18n/format.js';\nimport {\n goalsChecklistProgressSuffix,\n goalsContinuationChecklistTemplate,\n goalsContinuationPlainTemplate,\n goalsEvaluateCopy,\n goalsJudgeReason,\n goalsJudgeResponseLanguageNote,\n JUDGE_REASON_EN,\n type JudgeReasonId,\n} from '../../i18n/goals-bundle.js';\nimport {\n DEFAULT_SERVER_LOCALE,\n normalizeServerLocale,\n SERVER_LOCALES,\n type ServerLocale,\n serverLocaleOrFallback,\n isServerLocale,\n} from '../../i18n/locale.js';\n\n// ── Goal-facing aliases (persistent goal uses same locale set as server i18n) ──\n\nexport const GOAL_UI_LOCALES = SERVER_LOCALES;\nexport type GoalUiLocale = ServerLocale;\nexport const DEFAULT_GOAL_UI_LOCALE = DEFAULT_SERVER_LOCALE;\n\nexport const isGoalUiLocale = isServerLocale;\nexport const normalizeGoalUiLocale = normalizeServerLocale;\nexport const goalUiLocaleOrFallback = serverLocaleOrFallback;\n\nexport function resolveGoalUiLocale(state: PersistentGoalState | undefined | null): GoalUiLocale {\n return goalUiLocaleOrFallback(state?.uiLocale);\n}\n\n// ── Hermes-style English continuation (tests / parity; sourced from server i18n JSON) ──\n\nexport const CONTINUATION_PROMPT_TEMPLATE_EN = goalsContinuationPlainTemplate('en');\nexport const CONTINUATION_PROMPT_WITH_CHECKLIST_TEMPLATE_EN = goalsContinuationChecklistTemplate('en');\n\nexport function buildContinuationPromptFromState(state: PersistentGoalState, locale: GoalUiLocale): string {\n const L = goalUiLocaleOrFallback(locale);\n const cl = state.checklist ?? [];\n if (cl.length) {\n const plain = renderChecklistPlain(cl);\n const { total, completed, impossible } = checklistCounts(cl);\n const done = completed + impossible;\n const tpl = goalsContinuationChecklistTemplate(L);\n return formatI18n(tpl, {\n goal: state.goal,\n done,\n total,\n checklist: plain,\n });\n }\n return formatI18n(goalsContinuationPlainTemplate(L), { goal: state.goal });\n}\n\nexport function judgeResponseLanguageNote(locale: GoalUiLocale): string {\n return goalsJudgeResponseLanguageNote(goalUiLocaleOrFallback(locale));\n}\n\nexport { JUDGE_REASON_EN, type JudgeReasonId };\n\nconst JUDGE_REASON_ID_BY_EN = new Map<string, JudgeReasonId>(\n (Object.entries(JUDGE_REASON_EN) as [JudgeReasonId, string][]).map(([id, s]) => [s, id]),\n);\n\nexport function judgeReasonText(id: JudgeReasonId, locale: GoalUiLocale): string {\n return goalsJudgeReason(id, goalUiLocaleOrFallback(locale));\n}\n\nexport function localizeJudgeReasonText(reason: string, locale: GoalUiLocale): string {\n const id = JUDGE_REASON_ID_BY_EN.get(reason);\n if (!id) return reason;\n return judgeReasonText(id, locale);\n}\n\nexport function judgeFreeformBuiltinMessages(locale: GoalUiLocale) {\n const L = goalUiLocaleOrFallback(locale);\n return {\n emptyGoal: judgeReasonText('empty_goal', L),\n emptyResponse: judgeReasonText('empty_response', L),\n noModel: judgeReasonText('judge_model_not_configured', L),\n callFailed: judgeReasonText('judge_call_failed', L),\n };\n}\n\nexport function checklistProgressSuffix(done: number, total: number, locale: GoalUiLocale): string {\n return goalsChecklistProgressSuffix(done, total, goalUiLocaleOrFallback(locale));\n}\n\nexport type GoalEvaluateUserCopyPack = ReturnType<typeof goalsEvaluateCopy>;\n\nexport function goalEvaluateUserCopy(locale: GoalUiLocale): GoalEvaluateUserCopyPack {\n return goalsEvaluateCopy(goalUiLocaleOrFallback(locale));\n}\n\n/** Persist `uiLocale` on the standing goal when the gateway console language is known. */\nexport function mergePersistentGoalUiLocale(\n customData: Record<string, unknown> | undefined,\n locale: GoalUiLocale | undefined,\n): Record<string, unknown> | undefined {\n if (!locale) return customData;\n const canonical = goalUiLocaleOrFallback(locale);\n const g = readPersistentGoal(customData);\n if (!g || g.status === 'cleared') return customData;\n if (g.uiLocale === canonical) return customData;\n const next: PersistentGoalState = { ...g, uiLocale: canonical };\n return mergeCustomDataPatch(customData ?? {}, {\n [PERSISTENT_GOAL_CUSTOM_KEY]: serializePersistentGoal(next),\n });\n}\n"],"mappings":";;;;;;AAgCA,MAAa,kBAAkB;AAE/B,MAAa,yBAAA;AAEb,MAAa,iBAAiB;AAC9B,MAAa,wBAAwB;AACrC,MAAa,yBAAyB;AAEtC,SAAgB,oBAAoB,OAA6D;AAC/F,QAAO,uBAAuB,OAAO,SAAS;;AAKhD,MAAa,kCAAkC,+BAA+B,KAAK;AACnF,MAAa,iDAAiD,mCAAmC,KAAK;AAEtG,SAAgB,iCAAiC,OAA4B,QAA8B;CACzG,MAAM,IAAI,uBAAuB,OAAO;CACxC,MAAM,KAAK,MAAM,aAAa,EAAE;AAChC,KAAI,GAAG,QAAQ;EACb,MAAM,QAAQ,qBAAqB,GAAG;EACtC,MAAM,EAAE,OAAO,WAAW,eAAe,gBAAgB,GAAG;EAC5D,MAAM,OAAO,YAAY;AAEzB,SAAO,WADK,mCAAmC,EAC1B,EAAE;GACrB,MAAM,MAAM;GACZ;GACA;GACA,WAAW;GACZ,CAAC;;AAEJ,QAAO,WAAW,+BAA+B,EAAE,EAAE,EAAE,MAAM,MAAM,MAAM,CAAC;;AAG5E,SAAgB,0BAA0B,QAA8B;AACtE,QAAO,+BAA+B,uBAAuB,OAAO,CAAC;;AAKvE,MAAM,wBAAwB,IAAI,IAC/B,OAAO,QAAQ,gBAAgB,CAA+B,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,GAAG,CAAC,CACzF;AAED,SAAgB,gBAAgB,IAAmB,QAA8B;AAC/E,QAAO,iBAAiB,IAAI,uBAAuB,OAAO,CAAC;;AAG7D,SAAgB,wBAAwB,QAAgB,QAA8B;CACpF,MAAM,KAAK,sBAAsB,IAAI,OAAO;AAC5C,KAAI,CAAC,GAAI,QAAO;AAChB,QAAO,gBAAgB,IAAI,OAAO;;AAGpC,SAAgB,6BAA6B,QAAsB;CACjE,MAAM,IAAI,uBAAuB,OAAO;AACxC,QAAO;EACL,WAAW,gBAAgB,cAAc,EAAE;EAC3C,eAAe,gBAAgB,kBAAkB,EAAE;EACnD,SAAS,gBAAgB,8BAA8B,EAAE;EACzD,YAAY,gBAAgB,qBAAqB,EAAE;EACpD;;AAGH,SAAgB,wBAAwB,MAAc,OAAe,QAA8B;AACjG,QAAO,6BAA6B,MAAM,OAAO,uBAAuB,OAAO,CAAC;;AAKlF,SAAgB,qBAAqB,QAAgD;AACnF,QAAO,kBAAkB,uBAAuB,OAAO,CAAC;;;AAI1D,SAAgB,4BACd,YACA,QACqC;AACrC,KAAI,CAAC,OAAQ,QAAO;CACpB,MAAM,YAAY,uBAAuB,OAAO;CAChD,MAAM,IAAI,mBAAmB,WAAW;AACxC,KAAI,CAAC,KAAK,EAAE,WAAW,UAAW,QAAO;AACzC,KAAI,EAAE,aAAa,UAAW,QAAO;CACrC,MAAM,OAA4B;EAAE,GAAG;EAAG,UAAU;EAAW;AAC/D,QAAO,qBAAqB,cAAc,EAAE,EAAE,GAC3C,6BAA6B,wBAAwB,KAAK,EAC5D,CAAC"}
1
+ {"version":3,"file":"goal-locale.js","names":[],"sources":["../../../../src/agent/goals/goal-locale.ts"],"sourcesContent":["import { checklistCounts } from './checklist-types.js';\nimport {\n renderChecklistPlain,\n type PersistentGoalState,\n} from './state.js';\n\nimport { formatI18n } from '../../i18n/format.js';\nimport {\n goalsChecklistProgressSuffix,\n goalsContinuationChecklistTemplate,\n goalsContinuationPlainTemplate,\n goalsEvaluateCopy,\n goalsJudgeReason,\n goalsJudgeResponseLanguageNote,\n JUDGE_REASON_EN,\n type JudgeReasonId,\n} from '../../i18n/goals-bundle.js';\nimport {\n DEFAULT_SERVER_LOCALE,\n normalizeServerLocale,\n SERVER_LOCALES,\n type ServerLocale,\n serverLocaleOrFallback,\n isServerLocale,\n} from '../../i18n/locale.js';\n\n// ── Goal-facing aliases (persistent goal uses same locale set as server i18n) ──\n\nexport const GOAL_UI_LOCALES = SERVER_LOCALES;\nexport type GoalUiLocale = ServerLocale;\nexport const DEFAULT_GOAL_UI_LOCALE = DEFAULT_SERVER_LOCALE;\n\nexport const isGoalUiLocale = isServerLocale;\nexport const normalizeGoalUiLocale = normalizeServerLocale;\nexport const goalUiLocaleOrFallback = serverLocaleOrFallback;\n\nexport function resolveGoalUiLocale(state: PersistentGoalState | undefined | null): GoalUiLocale {\n return goalUiLocaleOrFallback(state?.uiLocale);\n}\n\n// ── Hermes-style English continuation (tests / parity; sourced from server i18n JSON) ──\n\nexport const CONTINUATION_PROMPT_TEMPLATE_EN = goalsContinuationPlainTemplate('en');\nexport const CONTINUATION_PROMPT_WITH_CHECKLIST_TEMPLATE_EN = goalsContinuationChecklistTemplate('en');\n\nexport function buildContinuationPromptFromState(state: PersistentGoalState, locale: GoalUiLocale): string {\n const L = goalUiLocaleOrFallback(locale);\n const cl = state.checklist ?? [];\n if (cl.length) {\n const plain = renderChecklistPlain(cl);\n const { total, completed, impossible } = checklistCounts(cl);\n const done = completed + impossible;\n const tpl = goalsContinuationChecklistTemplate(L);\n return formatI18n(tpl, {\n goal: state.goal,\n done,\n total,\n checklist: plain,\n });\n }\n return formatI18n(goalsContinuationPlainTemplate(L), { goal: state.goal });\n}\n\nexport function judgeResponseLanguageNote(locale: GoalUiLocale): string {\n return goalsJudgeResponseLanguageNote(goalUiLocaleOrFallback(locale));\n}\n\nexport { JUDGE_REASON_EN, type JudgeReasonId };\n\nconst JUDGE_REASON_ID_BY_EN = new Map<string, JudgeReasonId>(\n (Object.entries(JUDGE_REASON_EN) as [JudgeReasonId, string][]).map(([id, s]) => [s, id]),\n);\n\nexport function judgeReasonText(id: JudgeReasonId, locale: GoalUiLocale): string {\n return goalsJudgeReason(id, goalUiLocaleOrFallback(locale));\n}\n\nexport function localizeJudgeReasonText(reason: string, locale: GoalUiLocale): string {\n const id = JUDGE_REASON_ID_BY_EN.get(reason);\n if (!id) return reason;\n return judgeReasonText(id, locale);\n}\n\nexport function judgeFreeformBuiltinMessages(locale: GoalUiLocale) {\n const L = goalUiLocaleOrFallback(locale);\n return {\n emptyGoal: judgeReasonText('empty_goal', L),\n emptyResponse: judgeReasonText('empty_response', L),\n noModel: judgeReasonText('judge_model_not_configured', L),\n callFailed: judgeReasonText('judge_call_failed', L),\n };\n}\n\nexport function checklistProgressSuffix(done: number, total: number, locale: GoalUiLocale): string {\n return goalsChecklistProgressSuffix(done, total, goalUiLocaleOrFallback(locale));\n}\n\nexport type GoalEvaluateUserCopyPack = ReturnType<typeof goalsEvaluateCopy>;\n\nexport function goalEvaluateUserCopy(locale: GoalUiLocale): GoalEvaluateUserCopyPack {\n return goalsEvaluateCopy(goalUiLocaleOrFallback(locale));\n}\n"],"mappings":";;;;;;AA4BA,MAAa,kBAAkB;AAE/B,MAAa,yBAAA;AAEb,MAAa,iBAAiB;AAC9B,MAAa,wBAAwB;AACrC,MAAa,yBAAyB;AAEtC,SAAgB,oBAAoB,OAA6D;AAC/F,QAAO,uBAAuB,OAAO,SAAS;;AAKhD,MAAa,kCAAkC,+BAA+B,KAAK;AACnF,MAAa,iDAAiD,mCAAmC,KAAK;AAEtG,SAAgB,iCAAiC,OAA4B,QAA8B;CACzG,MAAM,IAAI,uBAAuB,OAAO;CACxC,MAAM,KAAK,MAAM,aAAa,EAAE;AAChC,KAAI,GAAG,QAAQ;EACb,MAAM,QAAQ,qBAAqB,GAAG;EACtC,MAAM,EAAE,OAAO,WAAW,eAAe,gBAAgB,GAAG;EAC5D,MAAM,OAAO,YAAY;AAEzB,SAAO,WADK,mCAAmC,EAC1B,EAAE;GACrB,MAAM,MAAM;GACZ;GACA;GACA,WAAW;GACZ,CAAC;;AAEJ,QAAO,WAAW,+BAA+B,EAAE,EAAE,EAAE,MAAM,MAAM,MAAM,CAAC;;AAG5E,SAAgB,0BAA0B,QAA8B;AACtE,QAAO,+BAA+B,uBAAuB,OAAO,CAAC;;AAKvE,MAAM,wBAAwB,IAAI,IAC/B,OAAO,QAAQ,gBAAgB,CAA+B,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,GAAG,CAAC,CACzF;AAED,SAAgB,gBAAgB,IAAmB,QAA8B;AAC/E,QAAO,iBAAiB,IAAI,uBAAuB,OAAO,CAAC;;AAG7D,SAAgB,wBAAwB,QAAgB,QAA8B;CACpF,MAAM,KAAK,sBAAsB,IAAI,OAAO;AAC5C,KAAI,CAAC,GAAI,QAAO;AAChB,QAAO,gBAAgB,IAAI,OAAO;;AAGpC,SAAgB,6BAA6B,QAAsB;CACjE,MAAM,IAAI,uBAAuB,OAAO;AACxC,QAAO;EACL,WAAW,gBAAgB,cAAc,EAAE;EAC3C,eAAe,gBAAgB,kBAAkB,EAAE;EACnD,SAAS,gBAAgB,8BAA8B,EAAE;EACzD,YAAY,gBAAgB,qBAAqB,EAAE;EACpD;;AAGH,SAAgB,wBAAwB,MAAc,OAAe,QAA8B;AACjG,QAAO,6BAA6B,MAAM,OAAO,uBAAuB,OAAO,CAAC;;AAKlF,SAAgB,qBAAqB,QAAgD;AACnF,QAAO,kBAAkB,uBAAuB,OAAO,CAAC"}
@@ -20,6 +20,7 @@ import type { MessageBus } from '../../infra/bus/index.js';
20
20
  import type { ModelManager } from '../models/index.js';
21
21
  import type { SessionStore } from '../../session/store.js';
22
22
  import type { SessionStateBag } from '../session/index.js';
23
+ import type { GoalWithDetails } from '../../goals/types.js';
23
24
  import type { PersistentGoalApis } from './persistent-goal-apis.js';
24
25
  export interface PersistentGoalRouting {
25
26
  sessionKey: string;
@@ -50,6 +51,14 @@ export interface PersistentGoalServiceOptions {
50
51
  onSessionMetadataUpdated?: (sessionKey: string) => void;
51
52
  /** Push an assistant token + transcript refresh into a live webchat stream. */
52
53
  notifyWebchatTranscriptAppend: (sessionKey: string, assistantText: string) => void;
54
+ /** Gateway: durable goal status changed after post-turn judge. */
55
+ onGoalStatusUpdated?: (payload: {
56
+ goalId: string;
57
+ sessionKey: string;
58
+ previousStatus: string;
59
+ status: string;
60
+ goal: GoalWithDetails;
61
+ }) => void;
53
62
  }
54
63
  export declare class PersistentGoalService {
55
64
  private readonly opts;
@@ -121,7 +121,8 @@ var PersistentGoalService = class {
121
121
  skipPersistentGoalPostTurn: payload.skipPersistentGoalPostTurn ?? false,
122
122
  config: this.opts.getConfig(),
123
123
  runtimeSessionModelRef,
124
- publishVerdictToChannel: publishVerdict
124
+ publishVerdictToChannel: publishVerdict,
125
+ onGoalStatusUpdated: this.opts.onGoalStatusUpdated
125
126
  });
126
127
  }
127
128
  };
@@ -1 +1 @@
1
- {"version":3,"file":"persistent-goal-service.js","names":["parseRoutingSessionKey"],"sources":["../../../../src/agent/goals/persistent-goal-service.ts"],"sourcesContent":["/**\n * PersistentGoalService — owns the \"/goal\" runtime: continuation scheduling,\n * the `PersistentGoalApis` bag that command handlers receive, and the post-turn\n * verdict hook called from `OutboundCoordinator`.\n *\n * Previously this logic was scattered across `AgentService`:\n * - `setPersistentGoalWebchatContinuationScheduler` + a private callback field\n * - `schedulePersistentGoalContinuation` (bus vs webchat fork)\n * - `getPersistentGoalApisForCommand` (~40-line API factory)\n * - `recordPersistentGoalStreamOutcome` / `takePersistentGoalStreamOutcome`\n * - the `/goal` half of `emitSessionTurnComplete` (delegated to\n * `handlePersistentGoalPostTurn`)\n *\n * Concentrating it here gives the rest of `AgentService` a cleaner surface\n * (one collaborator instead of five methods) and makes the goal runtime\n * unit-testable in isolation.\n */\n\nimport type { AgentMessage } from '@earendil-works/pi-agent-core';\n\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport type { ModelManager } from '../models/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport type { SessionStateBag } from '../session/index.js';\nimport { parseSessionKey as parseRoutingSessionKey } from '../../routing/session-key.js';\nimport { createLogger } from '../../utils/logger.js';\nimport type { PersistentGoalApis } from './persistent-goal-apis.js';\nimport { handlePersistentGoalPostTurn } from './post-turn.js';\n\nconst log = createLogger('PersistentGoalService');\n\nexport interface PersistentGoalRouting {\n sessionKey: string;\n channel: string;\n chatId: string;\n inboundMetadata?: Record<string, unknown>;\n}\n\nexport interface SessionTurnCompletionForGoal {\n sessionKey: string;\n channel: string;\n chatId: string;\n assistantPlainText: string;\n aborted: boolean;\n streamError?: string;\n skipPersistentGoalPostTurn?: boolean;\n outboundMetadata?: Record<string, unknown>;\n}\n\nexport interface PersistentGoalServiceOptions {\n bus: MessageBus;\n sessionStore: SessionStore;\n modelManager: ModelManager;\n sessionState: SessionStateBag;\n /** Effective config snapshot accessor. */\n getConfig: () => Config | undefined;\n /** Resolve the workspace directory for `appendAssistantReceipt` writes. */\n getResolvedWorkspaceForSession: (sessionKey: string) => string;\n /** Notify the gateway UI after a metadata change (replaces the in-bag emit). */\n onSessionMetadataUpdated?: (sessionKey: string) => void;\n /** Push an assistant token + transcript refresh into a live webchat stream. */\n notifyWebchatTranscriptAppend: (sessionKey: string, assistantText: string) => void;\n}\n\nexport class PersistentGoalService {\n private readonly opts: PersistentGoalServiceOptions;\n /** Gateway only: webchat continuations bypass the bus and reuse `runGatewayAgent`. */\n private webchatContinuationScheduler?: (sessionKey: string, message: string) => void;\n\n constructor(opts: PersistentGoalServiceOptions) {\n this.opts = opts;\n }\n\n /** Register the gateway-side webchat continuation hook (set from `web-agent` wiring). */\n setWebchatContinuationScheduler(\n fn: ((sessionKey: string, message: string) => void) | undefined,\n ): void {\n this.webchatContinuationScheduler = fn;\n }\n\n /**\n * Continue a session after `/goal` decides the previous turn needs follow-up.\n * Webchat sessions go through the scheduler; bus-driven channels re-publish the\n * follow-up message as an inbound bus event so the existing inbound loop picks it up.\n */\n scheduleContinuation(\n sessionKey: string,\n message: string,\n routing: { channel: string; chatId: string; inboundMetadata?: Record<string, unknown> },\n ): void {\n const parsed = parseRoutingSessionKey(sessionKey);\n if (parsed?.source === 'webchat' && this.webchatContinuationScheduler) {\n this.webchatContinuationScheduler(sessionKey, message);\n return;\n }\n queueMicrotask(() => {\n void this.opts.bus\n .publishInbound({\n channel: routing.channel,\n chat_id: routing.chatId,\n sender_id: 'persistent-goal',\n content: message,\n metadata: { sessionKey, ...routing.inboundMetadata },\n })\n .catch((err) => {\n log.warn({ err, sessionKey }, 'Persistent goal: publishInbound failed');\n });\n });\n }\n\n /** Build the per-command `PersistentGoalApis` bag (transcript writers + scheduler closures). */\n buildApisForRouting(routing: PersistentGoalRouting): PersistentGoalApis {\n return {\n getSessionMetadata: (k) => this.opts.sessionStore.getMetadata(k),\n updateSessionMetadata: async (k, u) => {\n await this.opts.sessionStore.updateMetadata(k, u);\n this.opts.onSessionMetadataUpdated?.(k);\n },\n loadMessages: (k) => this.opts.sessionStore.loadMessages(k),\n appendAssistantReceipt: async (k, text) => {\n const trimmed = text.trim();\n if (!trimmed) return;\n await this.opts.sessionStore.appendTranscriptMessage(k, {\n role: 'assistant',\n content: [{ type: 'text', text: trimmed }],\n timestamp: Date.now(),\n } as AgentMessage);\n this.opts.notifyWebchatTranscriptAppend(k, trimmed);\n },\n scheduleContinuation: (sk, msg) => {\n this.scheduleContinuation(sk, msg, {\n channel: routing.channel,\n chatId: routing.chatId,\n inboundMetadata: routing.inboundMetadata,\n });\n },\n inboundConcurrentDepth: (sk) => this.opts.sessionState.getInboundTurnDepth(sk),\n };\n }\n\n recordStreamOutcome(sessionKey: string, outcome: { skipPersistentGoalPostTurn: boolean }): void {\n this.opts.sessionState.recordPersistentGoalStreamOutcome(sessionKey, outcome);\n }\n\n takeStreamOutcome(sessionKey: string): { skipPersistentGoalPostTurn: boolean } | undefined {\n return this.opts.sessionState.takePersistentGoalStreamOutcome(sessionKey);\n }\n\n /**\n * Run the `/goal` post-turn verdict for a completed user turn (called from\n * `OutboundCoordinator.emitSessionTurnComplete`).\n */\n async runPostTurn(payload: SessionTurnCompletionForGoal): Promise<void> {\n const apis = this.buildApisForRouting({\n sessionKey: payload.sessionKey,\n channel: payload.channel,\n chatId: payload.chatId,\n inboundMetadata: payload.outboundMetadata,\n });\n\n const src = parseRoutingSessionKey(payload.sessionKey)?.source;\n const isWebchat = src === 'webchat';\n const publishVerdict =\n !isWebchat && payload.channel !== 'cli'\n ? async (text: string) => {\n await this.opts.bus.publishOutbound({\n channel: payload.channel,\n chat_id: payload.chatId,\n content: text,\n type: 'message',\n metadata: {\n accountId: payload.outboundMetadata?.accountId,\n threadId: payload.outboundMetadata?.threadId,\n },\n });\n }\n : undefined;\n\n let runtimeSessionModelRef: string | undefined;\n try {\n runtimeSessionModelRef = this.opts.modelManager.getModelForSession(payload.sessionKey);\n } catch {\n runtimeSessionModelRef = undefined;\n }\n\n await handlePersistentGoalPostTurn({\n apis,\n sessionKey: payload.sessionKey,\n assistantPlainText: payload.assistantPlainText,\n aborted: payload.aborted,\n ...(payload.streamError !== undefined ? { streamError: payload.streamError } : {}),\n skipPersistentGoalPostTurn: payload.skipPersistentGoalPostTurn ?? false,\n config: this.opts.getConfig(),\n runtimeSessionModelRef,\n publishVerdictToChannel: publishVerdict,\n });\n }\n}\n"],"mappings":";;;;;kBAyByF;aACpC;AAIrD,MAAM,MAAM,aAAa,wBAAwB;AAmCjD,IAAa,wBAAb,MAAmC;CACjC;;CAEA;CAEA,YAAY,MAAoC;AAC9C,OAAK,OAAO;;;CAId,gCACE,IACM;AACN,OAAK,+BAA+B;;;;;;;CAQtC,qBACE,YACA,SACA,SACM;AAEN,MADeA,gBAAuB,WAC5B,EAAE,WAAW,aAAa,KAAK,8BAA8B;AACrE,QAAK,6BAA6B,YAAY,QAAQ;AACtD;;AAEF,uBAAqB;AACd,QAAK,KAAK,IACZ,eAAe;IACd,SAAS,QAAQ;IACjB,SAAS,QAAQ;IACjB,WAAW;IACX,SAAS;IACT,UAAU;KAAE;KAAY,GAAG,QAAQ;KAAiB;IACrD,CAAC,CACD,OAAO,QAAQ;AACd,QAAI,KAAK;KAAE;KAAK;KAAY,EAAE,yCAAyC;KACvE;IACJ;;;CAIJ,oBAAoB,SAAoD;AACtE,SAAO;GACL,qBAAqB,MAAM,KAAK,KAAK,aAAa,YAAY,EAAE;GAChE,uBAAuB,OAAO,GAAG,MAAM;AACrC,UAAM,KAAK,KAAK,aAAa,eAAe,GAAG,EAAE;AACjD,SAAK,KAAK,2BAA2B,EAAE;;GAEzC,eAAe,MAAM,KAAK,KAAK,aAAa,aAAa,EAAE;GAC3D,wBAAwB,OAAO,GAAG,SAAS;IACzC,MAAM,UAAU,KAAK,MAAM;AAC3B,QAAI,CAAC,QAAS;AACd,UAAM,KAAK,KAAK,aAAa,wBAAwB,GAAG;KACtD,MAAM;KACN,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;MAAS,CAAC;KAC1C,WAAW,KAAK,KAAK;KACtB,CAAiB;AAClB,SAAK,KAAK,8BAA8B,GAAG,QAAQ;;GAErD,uBAAuB,IAAI,QAAQ;AACjC,SAAK,qBAAqB,IAAI,KAAK;KACjC,SAAS,QAAQ;KACjB,QAAQ,QAAQ;KAChB,iBAAiB,QAAQ;KAC1B,CAAC;;GAEJ,yBAAyB,OAAO,KAAK,KAAK,aAAa,oBAAoB,GAAG;GAC/E;;CAGH,oBAAoB,YAAoB,SAAwD;AAC9F,OAAK,KAAK,aAAa,kCAAkC,YAAY,QAAQ;;CAG/E,kBAAkB,YAAyE;AACzF,SAAO,KAAK,KAAK,aAAa,gCAAgC,WAAW;;;;;;CAO3E,MAAM,YAAY,SAAsD;EACtE,MAAM,OAAO,KAAK,oBAAoB;GACpC,YAAY,QAAQ;GACpB,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GAChB,iBAAiB,QAAQ;GAC1B,CAAC;EAIF,MAAM,iBACJ,EAHUA,gBAAuB,QAAQ,WAAW,EAAE,WAC9B,cAEV,QAAQ,YAAY,QAC9B,OAAO,SAAiB;AACtB,SAAM,KAAK,KAAK,IAAI,gBAAgB;IAClC,SAAS,QAAQ;IACjB,SAAS,QAAQ;IACjB,SAAS;IACT,MAAM;IACN,UAAU;KACR,WAAW,QAAQ,kBAAkB;KACrC,UAAU,QAAQ,kBAAkB;KACrC;IACF,CAAC;MAEJ,KAAA;EAEN,IAAI;AACJ,MAAI;AACF,4BAAyB,KAAK,KAAK,aAAa,mBAAmB,QAAQ,WAAW;UAChF;AACN,4BAAyB,KAAA;;AAG3B,QAAM,6BAA6B;GACjC;GACA,YAAY,QAAQ;GACpB,oBAAoB,QAAQ;GAC5B,SAAS,QAAQ;GACjB,GAAI,QAAQ,gBAAgB,KAAA,IAAY,EAAE,aAAa,QAAQ,aAAa,GAAG,EAAE;GACjF,4BAA4B,QAAQ,8BAA8B;GAClE,QAAQ,KAAK,KAAK,WAAW;GAC7B;GACA,yBAAyB;GAC1B,CAAC"}
1
+ {"version":3,"file":"persistent-goal-service.js","names":["parseRoutingSessionKey"],"sources":["../../../../src/agent/goals/persistent-goal-service.ts"],"sourcesContent":["/**\n * PersistentGoalService — owns the \"/goal\" runtime: continuation scheduling,\n * the `PersistentGoalApis` bag that command handlers receive, and the post-turn\n * verdict hook called from `OutboundCoordinator`.\n *\n * Previously this logic was scattered across `AgentService`:\n * - `setPersistentGoalWebchatContinuationScheduler` + a private callback field\n * - `schedulePersistentGoalContinuation` (bus vs webchat fork)\n * - `getPersistentGoalApisForCommand` (~40-line API factory)\n * - `recordPersistentGoalStreamOutcome` / `takePersistentGoalStreamOutcome`\n * - the `/goal` half of `emitSessionTurnComplete` (delegated to\n * `handlePersistentGoalPostTurn`)\n *\n * Concentrating it here gives the rest of `AgentService` a cleaner surface\n * (one collaborator instead of five methods) and makes the goal runtime\n * unit-testable in isolation.\n */\n\nimport type { AgentMessage } from '@earendil-works/pi-agent-core';\n\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport type { ModelManager } from '../models/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport type { SessionStateBag } from '../session/index.js';\nimport type { GoalWithDetails } from '../../goals/types.js';\nimport { parseSessionKey as parseRoutingSessionKey } from '../../routing/session-key.js';\nimport { createLogger } from '../../utils/logger.js';\nimport type { PersistentGoalApis } from './persistent-goal-apis.js';\nimport { handlePersistentGoalPostTurn } from './post-turn.js';\n\nconst log = createLogger('PersistentGoalService');\n\nexport interface PersistentGoalRouting {\n sessionKey: string;\n channel: string;\n chatId: string;\n inboundMetadata?: Record<string, unknown>;\n}\n\nexport interface SessionTurnCompletionForGoal {\n sessionKey: string;\n channel: string;\n chatId: string;\n assistantPlainText: string;\n aborted: boolean;\n streamError?: string;\n skipPersistentGoalPostTurn?: boolean;\n outboundMetadata?: Record<string, unknown>;\n}\n\nexport interface PersistentGoalServiceOptions {\n bus: MessageBus;\n sessionStore: SessionStore;\n modelManager: ModelManager;\n sessionState: SessionStateBag;\n /** Effective config snapshot accessor. */\n getConfig: () => Config | undefined;\n /** Resolve the workspace directory for `appendAssistantReceipt` writes. */\n getResolvedWorkspaceForSession: (sessionKey: string) => string;\n /** Notify the gateway UI after a metadata change (replaces the in-bag emit). */\n onSessionMetadataUpdated?: (sessionKey: string) => void;\n /** Push an assistant token + transcript refresh into a live webchat stream. */\n notifyWebchatTranscriptAppend: (sessionKey: string, assistantText: string) => void;\n /** Gateway: durable goal status changed after post-turn judge. */\n onGoalStatusUpdated?: (payload: {\n goalId: string;\n sessionKey: string;\n previousStatus: string;\n status: string;\n goal: GoalWithDetails;\n }) => void;\n}\n\nexport class PersistentGoalService {\n private readonly opts: PersistentGoalServiceOptions;\n /** Gateway only: webchat continuations bypass the bus and reuse `runGatewayAgent`. */\n private webchatContinuationScheduler?: (sessionKey: string, message: string) => void;\n\n constructor(opts: PersistentGoalServiceOptions) {\n this.opts = opts;\n }\n\n /** Register the gateway-side webchat continuation hook (set from `web-agent` wiring). */\n setWebchatContinuationScheduler(\n fn: ((sessionKey: string, message: string) => void) | undefined,\n ): void {\n this.webchatContinuationScheduler = fn;\n }\n\n /**\n * Continue a session after `/goal` decides the previous turn needs follow-up.\n * Webchat sessions go through the scheduler; bus-driven channels re-publish the\n * follow-up message as an inbound bus event so the existing inbound loop picks it up.\n */\n scheduleContinuation(\n sessionKey: string,\n message: string,\n routing: { channel: string; chatId: string; inboundMetadata?: Record<string, unknown> },\n ): void {\n const parsed = parseRoutingSessionKey(sessionKey);\n if (parsed?.source === 'webchat' && this.webchatContinuationScheduler) {\n this.webchatContinuationScheduler(sessionKey, message);\n return;\n }\n queueMicrotask(() => {\n void this.opts.bus\n .publishInbound({\n channel: routing.channel,\n chat_id: routing.chatId,\n sender_id: 'persistent-goal',\n content: message,\n metadata: { sessionKey, ...routing.inboundMetadata },\n })\n .catch((err) => {\n log.warn({ err, sessionKey }, 'Persistent goal: publishInbound failed');\n });\n });\n }\n\n /** Build the per-command `PersistentGoalApis` bag (transcript writers + scheduler closures). */\n buildApisForRouting(routing: PersistentGoalRouting): PersistentGoalApis {\n return {\n getSessionMetadata: (k) => this.opts.sessionStore.getMetadata(k),\n updateSessionMetadata: async (k, u) => {\n await this.opts.sessionStore.updateMetadata(k, u);\n this.opts.onSessionMetadataUpdated?.(k);\n },\n loadMessages: (k) => this.opts.sessionStore.loadMessages(k),\n appendAssistantReceipt: async (k, text) => {\n const trimmed = text.trim();\n if (!trimmed) return;\n await this.opts.sessionStore.appendTranscriptMessage(k, {\n role: 'assistant',\n content: [{ type: 'text', text: trimmed }],\n timestamp: Date.now(),\n } as AgentMessage);\n this.opts.notifyWebchatTranscriptAppend(k, trimmed);\n },\n scheduleContinuation: (sk, msg) => {\n this.scheduleContinuation(sk, msg, {\n channel: routing.channel,\n chatId: routing.chatId,\n inboundMetadata: routing.inboundMetadata,\n });\n },\n inboundConcurrentDepth: (sk) => this.opts.sessionState.getInboundTurnDepth(sk),\n };\n }\n\n recordStreamOutcome(sessionKey: string, outcome: { skipPersistentGoalPostTurn: boolean }): void {\n this.opts.sessionState.recordPersistentGoalStreamOutcome(sessionKey, outcome);\n }\n\n takeStreamOutcome(sessionKey: string): { skipPersistentGoalPostTurn: boolean } | undefined {\n return this.opts.sessionState.takePersistentGoalStreamOutcome(sessionKey);\n }\n\n /**\n * Run the `/goal` post-turn verdict for a completed user turn (called from\n * `OutboundCoordinator.emitSessionTurnComplete`).\n */\n async runPostTurn(payload: SessionTurnCompletionForGoal): Promise<void> {\n const apis = this.buildApisForRouting({\n sessionKey: payload.sessionKey,\n channel: payload.channel,\n chatId: payload.chatId,\n inboundMetadata: payload.outboundMetadata,\n });\n\n const src = parseRoutingSessionKey(payload.sessionKey)?.source;\n const isWebchat = src === 'webchat';\n const publishVerdict =\n !isWebchat && payload.channel !== 'cli'\n ? async (text: string) => {\n await this.opts.bus.publishOutbound({\n channel: payload.channel,\n chat_id: payload.chatId,\n content: text,\n type: 'message',\n metadata: {\n accountId: payload.outboundMetadata?.accountId,\n threadId: payload.outboundMetadata?.threadId,\n },\n });\n }\n : undefined;\n\n let runtimeSessionModelRef: string | undefined;\n try {\n runtimeSessionModelRef = this.opts.modelManager.getModelForSession(payload.sessionKey);\n } catch {\n runtimeSessionModelRef = undefined;\n }\n\n await handlePersistentGoalPostTurn({\n apis,\n sessionKey: payload.sessionKey,\n assistantPlainText: payload.assistantPlainText,\n aborted: payload.aborted,\n ...(payload.streamError !== undefined ? { streamError: payload.streamError } : {}),\n skipPersistentGoalPostTurn: payload.skipPersistentGoalPostTurn ?? false,\n config: this.opts.getConfig(),\n runtimeSessionModelRef,\n publishVerdictToChannel: publishVerdict,\n onGoalStatusUpdated: this.opts.onGoalStatusUpdated,\n });\n }\n}\n"],"mappings":";;;;;kBA0ByF;aACpC;AAIrD,MAAM,MAAM,aAAa,wBAAwB;AA2CjD,IAAa,wBAAb,MAAmC;CACjC;;CAEA;CAEA,YAAY,MAAoC;AAC9C,OAAK,OAAO;;;CAId,gCACE,IACM;AACN,OAAK,+BAA+B;;;;;;;CAQtC,qBACE,YACA,SACA,SACM;AAEN,MADeA,gBAAuB,WAC5B,EAAE,WAAW,aAAa,KAAK,8BAA8B;AACrE,QAAK,6BAA6B,YAAY,QAAQ;AACtD;;AAEF,uBAAqB;AACd,QAAK,KAAK,IACZ,eAAe;IACd,SAAS,QAAQ;IACjB,SAAS,QAAQ;IACjB,WAAW;IACX,SAAS;IACT,UAAU;KAAE;KAAY,GAAG,QAAQ;KAAiB;IACrD,CAAC,CACD,OAAO,QAAQ;AACd,QAAI,KAAK;KAAE;KAAK;KAAY,EAAE,yCAAyC;KACvE;IACJ;;;CAIJ,oBAAoB,SAAoD;AACtE,SAAO;GACL,qBAAqB,MAAM,KAAK,KAAK,aAAa,YAAY,EAAE;GAChE,uBAAuB,OAAO,GAAG,MAAM;AACrC,UAAM,KAAK,KAAK,aAAa,eAAe,GAAG,EAAE;AACjD,SAAK,KAAK,2BAA2B,EAAE;;GAEzC,eAAe,MAAM,KAAK,KAAK,aAAa,aAAa,EAAE;GAC3D,wBAAwB,OAAO,GAAG,SAAS;IACzC,MAAM,UAAU,KAAK,MAAM;AAC3B,QAAI,CAAC,QAAS;AACd,UAAM,KAAK,KAAK,aAAa,wBAAwB,GAAG;KACtD,MAAM;KACN,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;MAAS,CAAC;KAC1C,WAAW,KAAK,KAAK;KACtB,CAAiB;AAClB,SAAK,KAAK,8BAA8B,GAAG,QAAQ;;GAErD,uBAAuB,IAAI,QAAQ;AACjC,SAAK,qBAAqB,IAAI,KAAK;KACjC,SAAS,QAAQ;KACjB,QAAQ,QAAQ;KAChB,iBAAiB,QAAQ;KAC1B,CAAC;;GAEJ,yBAAyB,OAAO,KAAK,KAAK,aAAa,oBAAoB,GAAG;GAC/E;;CAGH,oBAAoB,YAAoB,SAAwD;AAC9F,OAAK,KAAK,aAAa,kCAAkC,YAAY,QAAQ;;CAG/E,kBAAkB,YAAyE;AACzF,SAAO,KAAK,KAAK,aAAa,gCAAgC,WAAW;;;;;;CAO3E,MAAM,YAAY,SAAsD;EACtE,MAAM,OAAO,KAAK,oBAAoB;GACpC,YAAY,QAAQ;GACpB,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GAChB,iBAAiB,QAAQ;GAC1B,CAAC;EAIF,MAAM,iBACJ,EAHUA,gBAAuB,QAAQ,WAAW,EAAE,WAC9B,cAEV,QAAQ,YAAY,QAC9B,OAAO,SAAiB;AACtB,SAAM,KAAK,KAAK,IAAI,gBAAgB;IAClC,SAAS,QAAQ;IACjB,SAAS,QAAQ;IACjB,SAAS;IACT,MAAM;IACN,UAAU;KACR,WAAW,QAAQ,kBAAkB;KACrC,UAAU,QAAQ,kBAAkB;KACrC;IACF,CAAC;MAEJ,KAAA;EAEN,IAAI;AACJ,MAAI;AACF,4BAAyB,KAAK,KAAK,aAAa,mBAAmB,QAAQ,WAAW;UAChF;AACN,4BAAyB,KAAA;;AAG3B,QAAM,6BAA6B;GACjC;GACA,YAAY,QAAQ;GACpB,oBAAoB,QAAQ;GAC5B,SAAS,QAAQ;GACjB,GAAI,QAAQ,gBAAgB,KAAA,IAAY,EAAE,aAAa,QAAQ,aAAa,GAAG,EAAE;GACjF,4BAA4B,QAAQ,8BAA8B;GAClE,QAAQ,KAAK,KAAK,WAAW;GAC7B;GACA,yBAAyB;GACzB,qBAAqB,KAAK,KAAK;GAChC,CAAC"}
@@ -13,4 +13,11 @@ export declare function handlePersistentGoalPostTurn(opts: {
13
13
  signal?: AbortSignal;
14
14
  /** Hermes-style: verdict line also sent as a normal outbound message (non-webchat). */
15
15
  publishVerdictToChannel?: (text: string) => Promise<void>;
16
+ onGoalStatusUpdated?: (payload: {
17
+ goalId: string;
18
+ sessionKey: string;
19
+ previousStatus: string;
20
+ status: string;
21
+ goal: import('../../goals/types.js').GoalWithDetails;
22
+ }) => void;
16
23
  }): Promise<void>;
@@ -2,14 +2,15 @@ import { getAgentDefaultModelRef, init_schema } from "../../config/schema.js";
2
2
  import { resolveEffectiveAgentProfileForSession } from "../../config/agent-profile.js";
3
3
  import { createLogger } from "../../utils/logger/index.js";
4
4
  import { init_logger } from "../../utils/logger.js";
5
- import { PERSISTENT_GOAL_CUSTOM_KEY, mergeCustomDataPatch, readPersistentGoal, serializePersistentGoal } from "./state.js";
5
+ import { GoalService } from "../../goals/goal-service.js";
6
6
  import { resolveGoalUiLocale } from "./goal-locale.js";
7
7
  import { evaluateAfterTurnHermesLike } from "./evaluate-turn.js";
8
- import { appendGoalRun } from "./goal-run-store.js";
8
+ import "../../goals/index.js";
9
9
  //#region src/agent/goals/post-turn.ts
10
10
  init_schema();
11
11
  init_logger();
12
12
  const log = createLogger("PersistentGoal");
13
+ const goalService = new GoalService();
13
14
  function buildHistoryExcerpt(messages, maxChars) {
14
15
  if (maxChars <= 0) return "";
15
16
  try {
@@ -35,13 +36,32 @@ async function appendAssistantLine(apis, sessionKey, text) {
35
36
  await apis.appendAssistantReceipt(sessionKey, text);
36
37
  }
37
38
  async function handlePersistentGoalPostTurn(opts) {
38
- const { apis, sessionKey, assistantPlainText, aborted, streamError, skipPersistentGoalPostTurn, config, runtimeSessionModelRef, signal, publishVerdictToChannel } = opts;
39
+ const { apis, sessionKey, assistantPlainText, aborted, streamError, skipPersistentGoalPostTurn, config, runtimeSessionModelRef, signal, publishVerdictToChannel, onGoalStatusUpdated } = opts;
39
40
  if (skipPersistentGoalPostTurn) return;
40
41
  if (aborted || streamError) return;
41
- const meta = await apis.getSessionMetadata(sessionKey);
42
- if (!meta) return;
43
- const state = readPersistentGoal(meta.customData);
44
- if (!state || state.status !== "active") return;
42
+ if (!await apis.getSessionMetadata(sessionKey)) return;
43
+ const goal = goalService.getActiveForSession(sessionKey);
44
+ if (!goal || goal.status !== "active") return;
45
+ const state = {
46
+ goal: goal.title,
47
+ status: "active",
48
+ turnsUsed: goal.turnsUsed,
49
+ maxTurns: goal.maxTurns,
50
+ createdAt: goal.createdAt,
51
+ lastTurnAt: goal.updatedAt,
52
+ lastReason: goal.blockedReason,
53
+ judgeModelRef: goal.judgeModelRef,
54
+ decomposed: goal.checklist.length > 0 ? true : void 0,
55
+ uiLocale: goal.uiLocale,
56
+ checklist: goal.checklist.map((it) => ({
57
+ text: it.text,
58
+ status: it.status,
59
+ addedBy: it.addedBy,
60
+ addedAt: it.addedAt,
61
+ completedAt: it.completedAt,
62
+ evidence: it.evidenceSummary
63
+ }))
64
+ };
45
65
  const judgeRef = resolveJudgeModelRef(config, sessionKey, state.judgeModelRef, runtimeSessionModelRef);
46
66
  if (!judgeRef) {
47
67
  log.warn({ sessionKey }, "Persistent goal: no judge model ref; skipping post-turn");
@@ -63,23 +83,48 @@ async function handlePersistentGoalPostTurn(opts) {
63
83
  historyExcerpt,
64
84
  uiLocale: resolveGoalUiLocale(state)
65
85
  });
66
- const baseCustom = { ...meta.customData };
67
86
  if (decision.newState) {
68
- const merged = mergeCustomDataPatch(baseCustom, { [PERSISTENT_GOAL_CUSTOM_KEY]: serializePersistentGoal(decision.newState) });
69
- await apis.updateSessionMetadata(sessionKey, { customData: merged });
70
- }
71
- if (config) try {
72
- await appendGoalRun({
73
- config,
74
- sessionKey,
75
- decision,
76
- assistantPlainText
77
- });
78
- } catch (err) {
79
- log.warn({
80
- err,
81
- sessionKey
82
- }, `Persistent goal: goal run append failed: ${err instanceof Error ? err.message : String(err)}`);
87
+ const ns = decision.newState;
88
+ const completedChecklistItemIds = decision.completedChecklistItemIndexes?.map((index) => goal.checklist[index]?.id).filter((id) => typeof id === "string" && id.length > 0);
89
+ try {
90
+ const updatedGoal = goalService.syncPostTurnState({
91
+ goalId: goal.id,
92
+ sessionKey,
93
+ source: "chat",
94
+ status: ns.status === "done" ? "done" : decision.verdict === "blocked" ? "blocked" : decision.verdict === "needs_input" ? "needs_input" : ns.status === "paused" ? "paused" : "active",
95
+ turnsUsed: ns.turnsUsed,
96
+ maxTurns: ns.maxTurns,
97
+ reason: ns.pausedReason ?? decision.reason,
98
+ nextAction: decision.continuationPrompt ?? void 0,
99
+ assistantPreview: assistantPlainText,
100
+ verdict: decision.verdict === "done" ? "done" : decision.verdict === "decompose" ? "decompose" : decision.verdict === "blocked" ? "blocked" : decision.verdict === "needs_input" ? "needs_input" : "continue",
101
+ confidence: decision.confidence,
102
+ missingEvidence: decision.missingEvidence,
103
+ userQuestion: decision.userQuestion,
104
+ completedChecklistItemIds,
105
+ checklist: ns.checklist?.map((it) => ({
106
+ text: it.text,
107
+ status: it.status,
108
+ addedBy: it.addedBy,
109
+ addedAt: it.addedAt,
110
+ completedAt: it.completedAt,
111
+ evidenceSummary: it.evidence
112
+ }))
113
+ });
114
+ if (updatedGoal && updatedGoal.status !== goal.status) onGoalStatusUpdated?.({
115
+ goalId: goal.id,
116
+ sessionKey,
117
+ previousStatus: goal.status,
118
+ status: updatedGoal.status,
119
+ goal: updatedGoal
120
+ });
121
+ } catch (err) {
122
+ log.warn({
123
+ err,
124
+ sessionKey,
125
+ goalId: goal.id
126
+ }, `Persistent goal: SQLite goal update failed: ${err instanceof Error ? err.message : String(err)}`);
127
+ }
83
128
  }
84
129
  if (decision.message) if (publishVerdictToChannel) try {
85
130
  await publishVerdictToChannel(decision.message);
@@ -1 +1 @@
1
- {"version":3,"file":"post-turn.js","names":[],"sources":["../../../../src/agent/goals/post-turn.ts"],"sourcesContent":["import type { AgentMessage } from '@earendil-works/pi-agent-core';\n\nimport type { Config } from '../../config/schema.js';\nimport { getAgentDefaultModelRef } from '../../config/schema.js';\nimport { resolveEffectiveAgentProfileForSession } from '../../config/agent-profile.js';\nimport { createLogger } from '../../utils/logger.js';\n\nimport { evaluateAfterTurnHermesLike } from './evaluate-turn.js';\nimport { appendGoalRun } from './goal-run-store.js';\nimport { resolveGoalUiLocale } from './goal-locale.js';\nimport type { PersistentGoalApis } from './persistent-goal-apis.js';\nimport {\n PERSISTENT_GOAL_CUSTOM_KEY,\n mergeCustomDataPatch,\n readPersistentGoal,\n serializePersistentGoal,\n} from './state.js';\n\nconst log = createLogger('PersistentGoal');\n\nfunction buildHistoryExcerpt(messages: AgentMessage[], maxChars: number): string {\n if (maxChars <= 0) return '';\n try {\n const raw = JSON.stringify(messages);\n if (raw.length <= maxChars) return raw;\n return raw.slice(-maxChars);\n } catch {\n return '';\n }\n}\n\nfunction resolveJudgeModelRef(\n config: Config | undefined,\n sessionKey: string,\n storedJudge?: string,\n runtimeSessionModelRef?: string,\n): string | undefined {\n const fromCfg = config?.goals?.judgeModelRef?.trim();\n if (fromCfg) return fromCfg;\n if (storedJudge?.trim()) return storedJudge.trim();\n if (config) {\n const profile = resolveEffectiveAgentProfileForSession(config, sessionKey);\n if (profile.primaryModelRef?.trim()) return profile.primaryModelRef.trim();\n }\n if (runtimeSessionModelRef?.trim()) return runtimeSessionModelRef.trim();\n if (config) return getAgentDefaultModelRef(config);\n return undefined;\n}\n\nasync function appendAssistantLine(apis: PersistentGoalApis, sessionKey: string, text: string): Promise<void> {\n await apis.appendAssistantReceipt(sessionKey, text);\n}\n\nexport async function handlePersistentGoalPostTurn(opts: {\n apis: PersistentGoalApis;\n sessionKey: string;\n assistantPlainText: string;\n aborted: boolean;\n streamError?: string;\n skipPersistentGoalPostTurn: boolean;\n config: Config | undefined;\n /** Active session model (overrides, per-agent defaults) when goals/global defaults are unset. */\n runtimeSessionModelRef?: string;\n signal?: AbortSignal;\n /** Hermes-style: verdict line also sent as a normal outbound message (non-webchat). */\n publishVerdictToChannel?: (text: string) => Promise<void>;\n}): Promise<void> {\n const {\n apis,\n sessionKey,\n assistantPlainText,\n aborted,\n streamError,\n skipPersistentGoalPostTurn,\n config,\n runtimeSessionModelRef,\n signal,\n publishVerdictToChannel,\n } = opts;\n\n if (skipPersistentGoalPostTurn) return;\n if (aborted || streamError) return;\n\n const meta = await apis.getSessionMetadata(sessionKey);\n if (!meta) return;\n\n const state = readPersistentGoal(meta.customData as Record<string, unknown> | undefined);\n if (!state || state.status !== 'active') return;\n\n const judgeRef = resolveJudgeModelRef(config, sessionKey, state.judgeModelRef, runtimeSessionModelRef);\n if (!judgeRef) {\n log.warn({ sessionKey }, 'Persistent goal: no judge model ref; skipping post-turn');\n return;\n }\n\n const goalsCfg = config?.goals;\n const historyCap = goalsCfg?.checklistHistoryChars ?? 24_000;\n let historyExcerpt = '';\n try {\n const msgs = await apis.loadMessages(sessionKey);\n historyExcerpt = buildHistoryExcerpt(msgs, historyCap);\n } catch (err) {\n log.debug(\n { err, sessionKey },\n `Persistent goal: could not load messages for judge context: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n const decision = await evaluateAfterTurnHermesLike(state, assistantPlainText, judgeRef, signal, {\n goalsSlice: goalsCfg,\n historyExcerpt,\n uiLocale: resolveGoalUiLocale(state),\n });\n\n const baseCustom = { ...(meta.customData as Record<string, unknown> | undefined) };\n\n if (decision.newState) {\n const merged = mergeCustomDataPatch(baseCustom, {\n [PERSISTENT_GOAL_CUSTOM_KEY]: serializePersistentGoal(decision.newState),\n });\n await apis.updateSessionMetadata(sessionKey, { customData: merged });\n }\n\n if (config) {\n try {\n await appendGoalRun({\n config,\n sessionKey,\n decision,\n assistantPlainText,\n });\n } catch (err) {\n log.warn(\n { err, sessionKey },\n `Persistent goal: goal run append failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n if (decision.message) {\n if (publishVerdictToChannel) {\n try {\n await publishVerdictToChannel(decision.message);\n } catch (err) {\n log.warn(\n { err, sessionKey },\n `Persistent goal: channel verdict send failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n } else {\n try {\n await appendAssistantLine(apis, sessionKey, decision.message);\n } catch (err) {\n log.warn(\n { err, sessionKey },\n `Persistent goal: failed to append status message: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n }\n\n if (decision.shouldContinue && decision.continuationPrompt) {\n apis.scheduleContinuation(sessionKey, decision.continuationPrompt);\n }\n}\n"],"mappings":";;;;;;;;;aAGiE;aAEZ;AAarD,MAAM,MAAM,aAAa,iBAAiB;AAE1C,SAAS,oBAAoB,UAA0B,UAA0B;AAC/E,KAAI,YAAY,EAAG,QAAO;AAC1B,KAAI;EACF,MAAM,MAAM,KAAK,UAAU,SAAS;AACpC,MAAI,IAAI,UAAU,SAAU,QAAO;AACnC,SAAO,IAAI,MAAM,CAAC,SAAS;SACrB;AACN,SAAO;;;AAIX,SAAS,qBACP,QACA,YACA,aACA,wBACoB;CACpB,MAAM,UAAU,QAAQ,OAAO,eAAe,MAAM;AACpD,KAAI,QAAS,QAAO;AACpB,KAAI,aAAa,MAAM,CAAE,QAAO,YAAY,MAAM;AAClD,KAAI,QAAQ;EACV,MAAM,UAAU,uCAAuC,QAAQ,WAAW;AAC1E,MAAI,QAAQ,iBAAiB,MAAM,CAAE,QAAO,QAAQ,gBAAgB,MAAM;;AAE5E,KAAI,wBAAwB,MAAM,CAAE,QAAO,uBAAuB,MAAM;AACxE,KAAI,OAAQ,QAAO,wBAAwB,OAAO;;AAIpD,eAAe,oBAAoB,MAA0B,YAAoB,MAA6B;AAC5G,OAAM,KAAK,uBAAuB,YAAY,KAAK;;AAGrD,eAAsB,6BAA6B,MAajC;CAChB,MAAM,EACJ,MACA,YACA,oBACA,SACA,aACA,4BACA,QACA,wBACA,QACA,4BACE;AAEJ,KAAI,2BAA4B;AAChC,KAAI,WAAW,YAAa;CAE5B,MAAM,OAAO,MAAM,KAAK,mBAAmB,WAAW;AACtD,KAAI,CAAC,KAAM;CAEX,MAAM,QAAQ,mBAAmB,KAAK,WAAkD;AACxF,KAAI,CAAC,SAAS,MAAM,WAAW,SAAU;CAEzC,MAAM,WAAW,qBAAqB,QAAQ,YAAY,MAAM,eAAe,uBAAuB;AACtG,KAAI,CAAC,UAAU;AACb,MAAI,KAAK,EAAE,YAAY,EAAE,0DAA0D;AACnF;;CAGF,MAAM,WAAW,QAAQ;CACzB,MAAM,aAAa,UAAU,yBAAyB;CACtD,IAAI,iBAAiB;AACrB,KAAI;AAEF,mBAAiB,oBAAoB,MADlB,KAAK,aAAa,WAAW,EACL,WAAW;UAC/C,KAAK;AACZ,MAAI,MACF;GAAE;GAAK;GAAY,EACnB,+DAA+D,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAChH;;CAGH,MAAM,WAAW,MAAM,4BAA4B,OAAO,oBAAoB,UAAU,QAAQ;EAC9F,YAAY;EACZ;EACA,UAAU,oBAAoB,MAAM;EACrC,CAAC;CAEF,MAAM,aAAa,EAAE,GAAI,KAAK,YAAoD;AAElF,KAAI,SAAS,UAAU;EACrB,MAAM,SAAS,qBAAqB,YAAY,GAC7C,6BAA6B,wBAAwB,SAAS,SAAS,EACzE,CAAC;AACF,QAAM,KAAK,sBAAsB,YAAY,EAAE,YAAY,QAAQ,CAAC;;AAGtE,KAAI,OACF,KAAI;AACF,QAAM,cAAc;GAClB;GACA;GACA;GACA;GACD,CAAC;UACK,KAAK;AACZ,MAAI,KACF;GAAE;GAAK;GAAY,EACnB,4CAA4C,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAC7F;;AAIL,KAAI,SAAS,QACX,KAAI,wBACF,KAAI;AACF,QAAM,wBAAwB,SAAS,QAAQ;UACxC,KAAK;AACZ,MAAI,KACF;GAAE;GAAK;GAAY,EACnB,iDAAiD,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAClG;;KAGH,KAAI;AACF,QAAM,oBAAoB,MAAM,YAAY,SAAS,QAAQ;UACtD,KAAK;AACZ,MAAI,KACF;GAAE;GAAK;GAAY,EACnB,qDAAqD,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GACtG;;AAKP,KAAI,SAAS,kBAAkB,SAAS,mBACtC,MAAK,qBAAqB,YAAY,SAAS,mBAAmB"}
1
+ {"version":3,"file":"post-turn.js","names":[],"sources":["../../../../src/agent/goals/post-turn.ts"],"sourcesContent":["import type { AgentMessage } from '@earendil-works/pi-agent-core';\n\nimport type { Config } from '../../config/schema.js';\nimport { getAgentDefaultModelRef } from '../../config/schema.js';\nimport { resolveEffectiveAgentProfileForSession } from '../../config/agent-profile.js';\nimport { GoalService } from '../../goals/index.js';\nimport { createLogger } from '../../utils/logger.js';\n\nimport { evaluateAfterTurnHermesLike } from './evaluate-turn.js';\nimport { resolveGoalUiLocale } from './goal-locale.js';\nimport type { PersistentGoalApis } from './persistent-goal-apis.js';\nimport type { PersistentGoalState } from './state.js';\n\nconst log = createLogger('PersistentGoal');\nconst goalService = new GoalService();\n\nfunction buildHistoryExcerpt(messages: AgentMessage[], maxChars: number): string {\n if (maxChars <= 0) return '';\n try {\n const raw = JSON.stringify(messages);\n if (raw.length <= maxChars) return raw;\n return raw.slice(-maxChars);\n } catch {\n return '';\n }\n}\n\nfunction resolveJudgeModelRef(\n config: Config | undefined,\n sessionKey: string,\n storedJudge?: string,\n runtimeSessionModelRef?: string,\n): string | undefined {\n const fromCfg = config?.goals?.judgeModelRef?.trim();\n if (fromCfg) return fromCfg;\n if (storedJudge?.trim()) return storedJudge.trim();\n if (config) {\n const profile = resolveEffectiveAgentProfileForSession(config, sessionKey);\n if (profile.primaryModelRef?.trim()) return profile.primaryModelRef.trim();\n }\n if (runtimeSessionModelRef?.trim()) return runtimeSessionModelRef.trim();\n if (config) return getAgentDefaultModelRef(config);\n return undefined;\n}\n\nasync function appendAssistantLine(apis: PersistentGoalApis, sessionKey: string, text: string): Promise<void> {\n await apis.appendAssistantReceipt(sessionKey, text);\n}\n\nexport async function handlePersistentGoalPostTurn(opts: {\n apis: PersistentGoalApis;\n sessionKey: string;\n assistantPlainText: string;\n aborted: boolean;\n streamError?: string;\n skipPersistentGoalPostTurn: boolean;\n config: Config | undefined;\n /** Active session model (overrides, per-agent defaults) when goals/global defaults are unset. */\n runtimeSessionModelRef?: string;\n signal?: AbortSignal;\n /** Hermes-style: verdict line also sent as a normal outbound message (non-webchat). */\n publishVerdictToChannel?: (text: string) => Promise<void>;\n onGoalStatusUpdated?: (payload: {\n goalId: string;\n sessionKey: string;\n previousStatus: string;\n status: string;\n goal: import('../../goals/types.js').GoalWithDetails;\n }) => void;\n}): Promise<void> {\n const {\n apis,\n sessionKey,\n assistantPlainText,\n aborted,\n streamError,\n skipPersistentGoalPostTurn,\n config,\n runtimeSessionModelRef,\n signal,\n publishVerdictToChannel,\n onGoalStatusUpdated,\n } = opts;\n\n if (skipPersistentGoalPostTurn) return;\n if (aborted || streamError) return;\n\n const meta = await apis.getSessionMetadata(sessionKey);\n if (!meta) return;\n\n const goal = goalService.getActiveForSession(sessionKey);\n if (!goal || goal.status !== 'active') return;\n\n const state: PersistentGoalState = {\n goal: goal.title,\n status: 'active',\n turnsUsed: goal.turnsUsed,\n maxTurns: goal.maxTurns,\n createdAt: goal.createdAt,\n lastTurnAt: goal.updatedAt,\n lastReason: goal.blockedReason,\n judgeModelRef: goal.judgeModelRef,\n decomposed: goal.checklist.length > 0 ? true : undefined,\n uiLocale: goal.uiLocale,\n checklist: goal.checklist.map((it) => ({\n text: it.text,\n status: it.status,\n addedBy: it.addedBy,\n addedAt: it.addedAt,\n completedAt: it.completedAt,\n evidence: it.evidenceSummary,\n })),\n };\n\n const judgeRef = resolveJudgeModelRef(config, sessionKey, state.judgeModelRef, runtimeSessionModelRef);\n if (!judgeRef) {\n log.warn({ sessionKey }, 'Persistent goal: no judge model ref; skipping post-turn');\n return;\n }\n\n const goalsCfg = config?.goals;\n const historyCap = goalsCfg?.checklistHistoryChars ?? 24_000;\n let historyExcerpt = '';\n try {\n const msgs = await apis.loadMessages(sessionKey);\n historyExcerpt = buildHistoryExcerpt(msgs, historyCap);\n } catch (err) {\n log.debug(\n { err, sessionKey },\n `Persistent goal: could not load messages for judge context: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n const decision = await evaluateAfterTurnHermesLike(state, assistantPlainText, judgeRef, signal, {\n goalsSlice: goalsCfg,\n historyExcerpt,\n uiLocale: resolveGoalUiLocale(state),\n });\n\n if (decision.newState) {\n const ns = decision.newState;\n const completedChecklistItemIds = decision.completedChecklistItemIndexes\n ?.map((index) => goal.checklist[index]?.id)\n .filter((id): id is string => typeof id === 'string' && id.length > 0);\n try {\n const updatedGoal = goalService.syncPostTurnState({\n goalId: goal.id,\n sessionKey,\n source: 'chat',\n status: ns.status === 'done'\n ? 'done'\n : decision.verdict === 'blocked'\n ? 'blocked'\n : decision.verdict === 'needs_input'\n ? 'needs_input'\n : ns.status === 'paused'\n ? 'paused'\n : 'active',\n turnsUsed: ns.turnsUsed,\n maxTurns: ns.maxTurns,\n reason: ns.pausedReason ?? decision.reason,\n nextAction: decision.continuationPrompt ?? undefined,\n assistantPreview: assistantPlainText,\n verdict: decision.verdict === 'done'\n ? 'done'\n : decision.verdict === 'decompose'\n ? 'decompose'\n : decision.verdict === 'blocked'\n ? 'blocked'\n : decision.verdict === 'needs_input'\n ? 'needs_input'\n : 'continue',\n confidence: decision.confidence,\n missingEvidence: decision.missingEvidence,\n userQuestion: decision.userQuestion,\n completedChecklistItemIds,\n checklist: ns.checklist?.map((it) => ({\n text: it.text,\n status: it.status,\n addedBy: it.addedBy,\n addedAt: it.addedAt,\n completedAt: it.completedAt,\n evidenceSummary: it.evidence,\n })),\n });\n if (updatedGoal && updatedGoal.status !== goal.status) {\n onGoalStatusUpdated?.({\n goalId: goal.id,\n sessionKey,\n previousStatus: goal.status,\n status: updatedGoal.status,\n goal: updatedGoal,\n });\n }\n } catch (err) {\n log.warn(\n { err, sessionKey, goalId: goal.id },\n `Persistent goal: SQLite goal update failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n if (decision.message) {\n if (publishVerdictToChannel) {\n try {\n await publishVerdictToChannel(decision.message);\n } catch (err) {\n log.warn(\n { err, sessionKey },\n `Persistent goal: channel verdict send failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n } else {\n try {\n await appendAssistantLine(apis, sessionKey, decision.message);\n } catch (err) {\n log.warn(\n { err, sessionKey },\n `Persistent goal: failed to append status message: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n }\n\n if (decision.shouldContinue && decision.continuationPrompt) {\n apis.scheduleContinuation(sessionKey, decision.continuationPrompt);\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,5 @@
1
1
  import { type ChecklistItemStatus, type GoalChecklistItem } from './checklist-types.js';
2
2
  import type { ServerLocale as GoalUiLocale } from '../../i18n/locale.js';
3
- /** Persisted under `SessionMetadata.customData.persistentGoal`. */
4
- export declare const PERSISTENT_GOAL_CUSTOM_KEY = "persistentGoal";
5
3
  export type PersistentGoalStatus = 'active' | 'paused' | 'done' | 'cleared';
6
4
  export interface PersistentGoalState {
7
5
  goal: string;
@@ -25,8 +23,6 @@ export interface PersistentGoalState {
25
23
  export declare function defaultMaxTurns(cfg: {
26
24
  maxTurns?: number;
27
25
  } | undefined): number;
28
- export declare function readPersistentGoal(customData: Record<string, unknown> | undefined): PersistentGoalState | null;
29
- export declare function serializePersistentGoal(s: PersistentGoalState): Record<string, unknown>;
30
26
  /** Render checklist for continuation prompt (Hermes-style, no numbers in body). */
31
27
  export declare function renderChecklistPlain(items: GoalChecklistItem[]): string;
32
28
  /** Numbered checklist for judge user prompts (1-based indices). */
@@ -48,4 +44,3 @@ export declare function applyJudgeChecklistUpdates(items: GoalChecklistItem[], p
48
44
  text: string;
49
45
  }[];
50
46
  }): GoalChecklistItem[];
51
- export declare function mergeCustomDataPatch(existingCustom: Record<string, unknown> | undefined, patch: Record<string, unknown>): Record<string, unknown>;
@@ -1,99 +1,10 @@
1
1
  import { CHECKLIST_ITEM_PENDING, TERMINAL_CHECKLIST_STATUSES } from "./checklist-types.js";
2
2
  //#region src/agent/goals/state.ts
3
- /** Persisted under `SessionMetadata.customData.persistentGoal`. */
4
- const PERSISTENT_GOAL_CUSTOM_KEY = "persistentGoal";
5
3
  function defaultMaxTurns(cfg) {
6
4
  const n = cfg?.maxTurns;
7
5
  if (typeof n === "number" && Number.isFinite(n)) return Math.max(1, Math.min(500, Math.floor(n)));
8
6
  return 20;
9
7
  }
10
- function coerceStatus(s) {
11
- if (s === "active" || s === "paused" || s === "done" || s === "cleared") return s;
12
- }
13
- function coerceChecklistItem(raw) {
14
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
15
- const r = raw;
16
- const text = typeof r.text === "string" ? r.text.trim() : "";
17
- if (!text) return null;
18
- const st = typeof r.status === "string" ? r.status.trim().toLowerCase() : "";
19
- return {
20
- text,
21
- status: st === "completed" || st === "impossible" || st === "pending" ? st : CHECKLIST_ITEM_PENDING,
22
- addedBy: (typeof r.addedBy === "string" ? r.addedBy.trim().toLowerCase() : "") === "user" ? "user" : "judge",
23
- addedAt: typeof r.addedAt === "number" && Number.isFinite(r.addedAt) ? Math.floor(r.addedAt) : Date.now(),
24
- completedAt: typeof r.completedAt === "number" && Number.isFinite(r.completedAt) ? Math.floor(r.completedAt) : void 0,
25
- evidence: typeof r.evidence === "string" ? r.evidence : void 0
26
- };
27
- }
28
- function readPersistentGoal(customData) {
29
- if (!customData || typeof customData !== "object") return null;
30
- const raw = customData[PERSISTENT_GOAL_CUSTOM_KEY];
31
- if (raw && typeof raw === "object" && !Array.isArray(raw)) {
32
- const o = raw;
33
- const goal = typeof o.goal === "string" ? o.goal.trim() : "";
34
- if (!goal) return null;
35
- const status = coerceStatus(o.status) ?? "active";
36
- const maxTurns = typeof o.maxTurns === "number" && Number.isFinite(o.maxTurns) ? Math.max(1, Math.min(500, Math.floor(o.maxTurns))) : 20;
37
- const turnsUsed = typeof o.turnsUsed === "number" && Number.isFinite(o.turnsUsed) ? Math.max(0, Math.floor(o.turnsUsed)) : 0;
38
- const createdAt = typeof o.createdAt === "number" && Number.isFinite(o.createdAt) ? o.createdAt : Date.now();
39
- const lastTurnAt = typeof o.lastTurnAt === "number" && Number.isFinite(o.lastTurnAt) ? o.lastTurnAt : 0;
40
- const lastVerdict = o.lastVerdict === "done" || o.lastVerdict === "continue" || o.lastVerdict === "skipped" || o.lastVerdict === "decompose" ? o.lastVerdict : void 0;
41
- const lastReason = typeof o.lastReason === "string" ? o.lastReason : void 0;
42
- const pausedReason = typeof o.pausedReason === "string" ? o.pausedReason : void 0;
43
- const judgeModelRef = typeof o.judgeModelRef === "string" ? o.judgeModelRef.trim() : void 0;
44
- const consecutiveParseFailures = typeof o.consecutiveParseFailures === "number" && Number.isFinite(o.consecutiveParseFailures) ? Math.max(0, Math.floor(o.consecutiveParseFailures)) : 0;
45
- const decomposed = Boolean(o.decomposed);
46
- const uiLocale = o.uiLocale === "zh" || o.uiLocale === "en" ? o.uiLocale : void 0;
47
- const checklistRaw = o.checklist;
48
- const checklist = [];
49
- if (Array.isArray(checklistRaw)) for (const row of checklistRaw) {
50
- const it = coerceChecklistItem(row);
51
- if (it) checklist.push(it);
52
- }
53
- return {
54
- goal,
55
- status,
56
- turnsUsed,
57
- maxTurns,
58
- createdAt,
59
- lastTurnAt,
60
- lastVerdict,
61
- lastReason,
62
- pausedReason,
63
- judgeModelRef: judgeModelRef || void 0,
64
- consecutiveParseFailures,
65
- decomposed: decomposed || void 0,
66
- checklist: checklist.length ? checklist : void 0,
67
- uiLocale
68
- };
69
- }
70
- return null;
71
- }
72
- function serializePersistentGoal(s) {
73
- return {
74
- goal: s.goal,
75
- status: s.status,
76
- turnsUsed: s.turnsUsed,
77
- maxTurns: s.maxTurns,
78
- createdAt: s.createdAt,
79
- lastTurnAt: s.lastTurnAt,
80
- ...s.lastVerdict ? { lastVerdict: s.lastVerdict } : {},
81
- ...s.lastReason ? { lastReason: s.lastReason } : {},
82
- ...s.pausedReason ? { pausedReason: s.pausedReason } : {},
83
- ...s.judgeModelRef ? { judgeModelRef: s.judgeModelRef } : {},
84
- ...s.consecutiveParseFailures ? { consecutiveParseFailures: s.consecutiveParseFailures } : {},
85
- ...s.decomposed ? { decomposed: true } : {},
86
- ...s.uiLocale ? { uiLocale: s.uiLocale } : {},
87
- ...s.checklist?.length ? { checklist: s.checklist.map((it) => ({
88
- text: it.text,
89
- status: it.status,
90
- addedBy: it.addedBy,
91
- addedAt: it.addedAt,
92
- ...it.completedAt !== void 0 ? { completedAt: it.completedAt } : {},
93
- ...it.evidence ? { evidence: it.evidence } : {}
94
- })) } : {}
95
- };
96
- }
97
8
  /** Render checklist for continuation prompt (Hermes-style, no numbers in body). */
98
9
  function renderChecklistPlain(items) {
99
10
  if (!items.length) return "(empty)";
@@ -165,13 +76,7 @@ function applyJudgeChecklistUpdates(items, parsed) {
165
76
  }
166
77
  return next;
167
78
  }
168
- function mergeCustomDataPatch(existingCustom, patch) {
169
- return {
170
- ...existingCustom ?? {},
171
- ...patch
172
- };
173
- }
174
79
  //#endregion
175
- export { PERSISTENT_GOAL_CUSTOM_KEY, applyJudgeChecklistUpdates, defaultMaxTurns, mergeCustomDataPatch, mergeDecomposedChecklistItems, readPersistentGoal, renderChecklistNumbered, renderChecklistPlain, serializePersistentGoal };
80
+ export { applyJudgeChecklistUpdates, defaultMaxTurns, mergeDecomposedChecklistItems, renderChecklistNumbered, renderChecklistPlain };
176
81
 
177
82
  //# sourceMappingURL=state.js.map