@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.
- package/README.md +46 -4
- package/README.zh-CN.md +46 -4
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/Combination-BzaXOLd9.js +41 -0
- package/dist/gateway/static/root/assets/agent-avatar-dicebear-zlx9l5Yp.js +1 -0
- package/dist/gateway/static/root/assets/agent-browser-settings-page-B-0zGjt8.js +6 -0
- package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-Bz7JWjRM.js +1 -0
- package/dist/gateway/static/root/assets/agents-DwDnJlXT.js +71 -0
- package/dist/gateway/static/root/assets/app-management-settings-panel-DaQwdeCq.js +1 -0
- package/dist/gateway/static/root/assets/appearance-settings-D2zv6r3P.js +1 -0
- package/dist/gateway/static/root/assets/apps-page-BIppe_jj.js +1 -0
- package/dist/gateway/static/root/assets/archive-plugin-DEmu8eH7.js +1 -0
- package/dist/gateway/static/root/assets/attachment-load-B98lJoN5.js +2 -0
- package/dist/gateway/static/root/assets/{attachment-preview-renderer-CybMSIoS.js → attachment-preview-renderer-DonnL2dL.js} +1 -1
- package/dist/gateway/static/root/assets/binary-plugins-CL9QKmyo.js +2 -0
- package/dist/gateway/static/root/assets/block-editor-BOAhMAhT.js +180 -0
- package/dist/gateway/static/root/assets/channels-settings-Br8iRnXp.js +1 -0
- package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +1 -0
- package/dist/gateway/static/root/assets/code-editor-dZTY2dRW.js +1 -0
- package/dist/gateway/static/root/assets/config-api-0o1WYdz2.js +3 -0
- package/dist/gateway/static/root/assets/connectors-settings-DDvHo9in.js +2 -0
- package/dist/gateway/static/root/assets/cron-api-Dj_UZKST.js +1 -0
- package/dist/gateway/static/root/assets/cron-dreaming-jobs-nCMWCf0p.js +1 -0
- package/dist/gateway/static/root/assets/cron-page-Dv7GII9G.js +1 -0
- package/dist/gateway/static/root/assets/cron-schedule-picker-DH10KgD6.js +1 -0
- package/dist/gateway/static/root/assets/dist-By6Rh2ee.js +1 -0
- package/dist/gateway/static/root/assets/dist-CkobR7mk.js +1 -0
- package/dist/gateway/static/root/assets/dist-DokQNVMQ.js +1 -0
- package/dist/gateway/static/root/assets/dreaming-scene-BHMRVEUS.js +4585 -0
- package/dist/gateway/static/root/assets/dreaming-settings-L2rgZDQl.js +1 -0
- package/dist/gateway/static/root/assets/extension-debug-page-Cjx6pZVz.js +1 -0
- package/dist/gateway/static/root/assets/{extension-page-W1wiG38F.js → extension-page-BSPNL90V.js} +1 -1
- package/dist/gateway/static/root/assets/extension-settings-page-m_UQYkVc.js +1 -0
- package/dist/gateway/static/root/assets/fetch-Bs7in_4F.js +1 -0
- package/dist/gateway/static/root/assets/format-interval-label-CftJ5uXu.js +1 -0
- package/dist/gateway/static/root/assets/gateway-config-api-Clfck-hW.js +1 -0
- package/dist/gateway/static/root/assets/gateway-settings-CS177xni.js +1 -0
- package/dist/gateway/static/root/assets/gateway-startup-retry-BkjVJc38.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-kqJue0sE.js +1 -0
- package/dist/gateway/static/root/assets/goals-page-C0FujUB5.js +2 -0
- package/dist/gateway/static/root/assets/goals-settings-CJnzNSDo.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-config-api-Cp7CPuIn.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-ifSI1Wbh.js +1 -0
- package/dist/gateway/static/root/assets/html-workspace-editor-CQLWDiwE.js +1 -0
- package/dist/gateway/static/root/assets/index-COkF54xv.js +121 -0
- package/dist/gateway/static/root/assets/index-DIaSNGEO.css +1 -0
- package/dist/gateway/static/root/assets/interval-presets-B29Ss_2y.js +2 -0
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings--MI1rYl7.js +1 -0
- package/dist/gateway/static/root/assets/locale-store-DjbfSsfA.js +1 -0
- package/dist/gateway/static/root/assets/logs-page-BwrVNlyW.js +2 -0
- package/dist/gateway/static/root/assets/markdown-editor-AssmZFx4.js +2 -0
- package/dist/gateway/static/root/assets/markdown-split-B_oc9lJe.js +1 -0
- package/dist/gateway/static/root/assets/media-plugins-DLPvB5H3.js +1 -0
- package/dist/gateway/static/root/assets/mermaid-render-BbqDc_LQ.js +134 -0
- package/dist/gateway/static/root/assets/messages-Csef1aW7.js +3 -0
- package/dist/gateway/static/root/assets/middleware-Pd0e8Igk.js +1 -0
- package/dist/gateway/static/root/assets/models-hub-panel-DHGiTIvf.js +2 -0
- package/dist/gateway/static/root/assets/note-detail-page-BM7zlDiT.js +2 -0
- package/dist/gateway/static/root/assets/note-image-lightbox-rSqAgOi9.js +1 -0
- package/dist/gateway/static/root/assets/note-time-hm6JO_Wi.js +1 -0
- package/dist/gateway/static/root/assets/notes-page-C9ACGEty.js +1 -0
- package/dist/gateway/static/root/assets/preview-open-alternatives-Bw_N2oZi.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-BhcWIKuM.js +1 -0
- package/dist/gateway/static/root/assets/save-bar-controls-CNP2jmw0.js +1 -0
- package/dist/gateway/static/root/assets/schedule-field-BPAWui3P.js +1 -0
- package/dist/gateway/static/root/assets/schedule-summary-B-hdSRdR.js +1 -0
- package/dist/gateway/static/root/assets/schema-form-CDPzua9q.js +1 -0
- package/dist/gateway/static/root/assets/sessions-page-DzkpSDZr.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-BYS-rpzn.js +1 -0
- package/dist/gateway/static/root/assets/settings-collapsible-section-C9bff85B.js +1 -0
- package/dist/gateway/static/root/assets/settings-form-section-BsrK7TBF.js +1 -0
- package/dist/gateway/static/root/assets/settings-page-DWK4Zo7s.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-DJiksNu4.js +1 -0
- package/dist/gateway/static/root/assets/share-preview-page-DnutoY_S.js +2 -0
- package/dist/gateway/static/root/assets/shares-settings-6oRgJMpn.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-CU9i0nJV.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-ERbdWENm.js +2 -0
- package/dist/gateway/static/root/assets/system-settings-panel-qP1JDtDd.js +1 -0
- package/dist/gateway/static/root/assets/theme-store-CD2wtgZV.js +1 -0
- package/dist/gateway/static/root/assets/use-agent-defaults-form-D3FGVLZb.js +1 -0
- package/dist/gateway/static/root/assets/use-blob-object-url-D4BFuzZB.js +1 -0
- package/dist/gateway/static/root/assets/use-channel-catalog-C4mg1hjD.js +1 -0
- package/dist/gateway/static/root/assets/use-settings-tab-guard-F6C0mpJt.js +1 -0
- package/dist/gateway/static/root/assets/vendor-codemirror-CNP1wPe7.js +45 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-BnDDb6qO.js +1 -0
- package/dist/gateway/static/root/assets/voice-player-store-B2EwIhtY.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-page.utils-EYg_xBQS.js → workflow-page.utils-CRB7WX9l.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-2Fptr0je.js +18 -0
- package/dist/gateway/static/root/index.html +12 -10
- package/dist/package.js +1 -1
- package/dist/src/agent/goals/checklist-judge.d.ts +5 -0
- package/dist/src/agent/goals/checklist-judge.js +26 -2
- package/dist/src/agent/goals/checklist-judge.js.map +1 -1
- package/dist/src/agent/goals/evaluate-turn.d.ts +5 -1
- package/dist/src/agent/goals/evaluate-turn.js +29 -3
- package/dist/src/agent/goals/evaluate-turn.js.map +1 -1
- package/dist/src/agent/goals/goal-locale.d.ts +0 -2
- package/dist/src/agent/goals/goal-locale.js +2 -15
- package/dist/src/agent/goals/goal-locale.js.map +1 -1
- package/dist/src/agent/goals/persistent-goal-service.d.ts +9 -0
- package/dist/src/agent/goals/persistent-goal-service.js +2 -1
- package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
- package/dist/src/agent/goals/post-turn.d.ts +7 -0
- package/dist/src/agent/goals/post-turn.js +68 -23
- package/dist/src/agent/goals/post-turn.js.map +1 -1
- package/dist/src/agent/goals/state.d.ts +0 -5
- package/dist/src/agent/goals/state.js +1 -96
- package/dist/src/agent/goals/state.js.map +1 -1
- package/dist/src/agent/messaging/command-handler.d.ts +4 -0
- package/dist/src/agent/messaging/command-handler.js +6 -2
- package/dist/src/agent/messaging/command-handler.js.map +1 -1
- package/dist/src/agent/service/direct-turn-helpers.d.ts +2 -0
- package/dist/src/agent/service/direct-turn-helpers.js +3 -2
- package/dist/src/agent/service/direct-turn-helpers.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.js +10 -1
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service.js +20 -1
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/service.types.d.ts +8 -0
- package/dist/src/agent/tools/cronjob-tool.d.ts +2 -0
- package/dist/src/agent/tools/cronjob-tool.js +27 -4
- package/dist/src/agent/tools/cronjob-tool.js.map +1 -1
- package/dist/src/agent/tools/edit.d.ts +2 -0
- package/dist/src/agent/tools/edit.js +10 -0
- package/dist/src/agent/tools/edit.js.map +1 -1
- package/dist/src/agent/tools/factory.js +16 -3
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/goal-evidence-recorder.d.ts +6 -0
- package/dist/src/agent/tools/goal-evidence-recorder.js +34 -0
- package/dist/src/agent/tools/goal-evidence-recorder.js.map +1 -0
- package/dist/src/agent/tools/goal-tool.d.ts +19 -0
- package/dist/src/agent/tools/goal-tool.js +101 -0
- package/dist/src/agent/tools/goal-tool.js.map +1 -0
- package/dist/src/agent/tools/index.d.ts +1 -0
- package/dist/src/agent/tools/index.js +2 -1
- package/dist/src/agent/tools/shell.d.ts +2 -0
- package/dist/src/agent/tools/shell.js +17 -2
- package/dist/src/agent/tools/shell.js.map +1 -1
- package/dist/src/agent/tools/workflow-tool.d.ts +1 -0
- package/dist/src/agent/tools/workflow-tool.js +10 -2
- package/dist/src/agent/tools/workflow-tool.js.map +1 -1
- package/dist/src/agent/tools/write.d.ts +2 -0
- package/dist/src/agent/tools/write.js +11 -0
- package/dist/src/agent/tools/write.js.map +1 -1
- package/dist/src/channels/attachments/inbound-persist.d.ts +7 -0
- package/dist/src/channels/attachments/inbound-persist.js +20 -2
- package/dist/src/channels/attachments/inbound-persist.js.map +1 -1
- package/dist/src/chat-commands/builtins/goal.d.ts +1 -1
- package/dist/src/chat-commands/builtins/goal.js +55 -97
- package/dist/src/chat-commands/builtins/goal.js.map +1 -1
- package/dist/src/chat-commands/builtins/subgoal.d.ts +1 -1
- package/dist/src/chat-commands/builtins/subgoal.js +49 -108
- package/dist/src/chat-commands/builtins/subgoal.js.map +1 -1
- package/dist/src/chat-commands/builtins/workflow.js +132 -8
- package/dist/src/chat-commands/builtins/workflow.js.map +1 -1
- package/dist/src/chat-commands/context.d.ts +3 -0
- package/dist/src/chat-commands/context.js +5 -0
- package/dist/src/chat-commands/context.js.map +1 -1
- package/dist/src/chat-commands/types.d.ts +5 -0
- package/dist/src/cli/command-catalog.js +43 -0
- package/dist/src/cli/command-catalog.js.map +1 -1
- package/dist/src/cli/command-loaders.js +1 -0
- package/dist/src/cli/command-loaders.js.map +1 -1
- package/dist/src/cli/command-manifest.js +4 -0
- package/dist/src/cli/command-manifest.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/goal.d.ts +4 -0
- package/dist/src/cli/commands/goal.js +213 -0
- package/dist/src/cli/commands/goal.js.map +1 -0
- package/dist/src/cli/commands/onboard.js +11 -5
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/config/index.js +2 -2
- package/dist/src/config/schema.d.ts +115 -0
- package/dist/src/config/schema.js +63 -4
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/web-patch.d.ts +14 -0
- package/dist/src/config/web-patch.js +45 -6
- package/dist/src/config/web-patch.js.map +1 -1
- package/dist/src/cron/executor.d.ts +2 -0
- package/dist/src/cron/executor.js +25 -0
- package/dist/src/cron/executor.js.map +1 -1
- package/dist/src/cron/job-content.js +1 -0
- package/dist/src/cron/job-content.js.map +1 -1
- package/dist/src/cron/types.d.ts +19 -1
- package/dist/src/cron/validation.d.ts +20 -0
- package/dist/src/cron/validation.js +7 -0
- package/dist/src/cron/validation.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +14 -0
- package/dist/src/gateway/hono/routes/goals.d.ts +1 -1
- package/dist/src/gateway/hono/routes/goals.js +670 -173
- package/dist/src/gateway/hono/routes/goals.js.map +1 -1
- package/dist/src/gateway/hono/routes/home.d.ts +5 -0
- package/dist/src/gateway/hono/routes/home.js +88 -3
- package/dist/src/gateway/hono/routes/home.js.map +1 -1
- package/dist/src/gateway/hono/routes/notes.js +20 -14
- package/dist/src/gateway/hono/routes/notes.js.map +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +6 -2
- package/dist/src/gateway/hono/routes/workflows.js.map +1 -1
- package/dist/src/gateway/hono/sse.js.map +1 -1
- package/dist/src/gateway/service/agent-runner.d.ts +2 -0
- package/dist/src/gateway/service/agent-runner.js +6 -2
- package/dist/src/gateway/service/agent-runner.js.map +1 -1
- package/dist/src/gateway/service/run-gateway-agent.d.ts +3 -0
- package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
- package/dist/src/gateway/service.d.ts +8 -0
- package/dist/src/gateway/service.js +69 -2
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/goals/goal-notifications.d.ts +29 -0
- package/dist/src/goals/goal-notifications.js +154 -0
- package/dist/src/goals/goal-notifications.js.map +1 -0
- package/dist/src/goals/goal-queue-store.d.ts +16 -0
- package/dist/src/goals/goal-queue-store.js +131 -0
- package/dist/src/goals/goal-queue-store.js.map +1 -0
- package/dist/src/goals/goal-queue-types.d.ts +31 -0
- package/dist/src/goals/goal-queue-types.js +1 -0
- package/dist/src/goals/goal-runner.d.ts +17 -0
- package/dist/src/goals/goal-runner.js +127 -0
- package/dist/src/goals/goal-runner.js.map +1 -0
- package/dist/src/goals/goal-service.d.ts +77 -0
- package/dist/src/goals/goal-service.js +261 -0
- package/dist/src/goals/goal-service.js.map +1 -0
- package/dist/src/goals/goal-store.d.ts +38 -0
- package/dist/src/goals/goal-store.js +404 -0
- package/dist/src/goals/goal-store.js.map +1 -0
- package/dist/src/goals/goal-workflow-judge.d.ts +13 -0
- package/dist/src/goals/goal-workflow-judge.js +147 -0
- package/dist/src/goals/goal-workflow-judge.js.map +1 -0
- package/dist/src/goals/index.d.ts +10 -0
- package/dist/src/goals/index.js +7 -0
- package/dist/src/goals/types.d.ts +119 -0
- package/dist/src/goals/types.js +1 -0
- package/dist/src/storage/sqlite/migrations/006_add_goals.sql +108 -0
- package/dist/src/storage/sqlite/migrations/007_goal_run_judge_schema.sql +4 -0
- package/dist/src/storage/sqlite/migrations/008_goal_queue_workflow_runs.sql +53 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/storage/sqlite/schema.sql +163 -0
- package/dist/src/utils/logger/stats.d.ts +1 -1
- package/dist/src/workflows/domain/run.d.ts +1 -0
- package/dist/src/workflows/domain/run.js.map +1 -1
- package/dist/src/workflows/service/workflow-run-service.d.ts +1 -0
- package/dist/src/workflows/service/workflow-run-service.js +5 -1
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-run-service.types.d.ts +1 -0
- package/dist/src/workflows/service/workflow-session-bridge.js +7 -0
- package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
- package/dist/src/workflows/store/run-index-store.d.ts +8 -0
- package/dist/src/workflows/store/run-index-store.js +58 -0
- package/dist/src/workflows/store/run-index-store.js.map +1 -0
- package/dist/src/workflows/store/run-store.d.ts +2 -0
- package/dist/src/workflows/store/run-store.js +14 -21
- package/dist/src/workflows/store/run-store.js.map +1 -1
- package/package.json +9 -3
- package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +0 -41
- package/dist/gateway/static/root/assets/agents-CFFioJCI.js +0 -78
- package/dist/gateway/static/root/assets/apps-page-BYDmkbzG.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-CsbDaMvd.js +0 -1
- package/dist/gateway/static/root/assets/circle-check-C23XjkUj.js +0 -1
- package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +0 -1
- package/dist/gateway/static/root/assets/cron-page-Apk-7p4p.js +0 -1
- package/dist/gateway/static/root/assets/dist-DmGDgpy2.js +0 -1
- package/dist/gateway/static/root/assets/extension-debug-page-pxFC-tUa.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-COXSv6xP.js +0 -1
- package/dist/gateway/static/root/assets/fetch-CFdKBnE6.js +0 -1
- package/dist/gateway/static/root/assets/gateway-startup-retry-DdngdObI.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-config-api-DcmAMYmN.js +0 -1
- package/dist/gateway/static/root/assets/index-C_2yKRJX.js +0 -4845
- package/dist/gateway/static/root/assets/index-DI5_GsZt.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-DvTWUOzd.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-page-CZbdugWZ.js +0 -180
- package/dist/gateway/static/root/assets/note-time-RdyBZxj3.js +0 -1
- package/dist/gateway/static/root/assets/notes-page-mEAwy3e1.js +0 -1
- package/dist/gateway/static/root/assets/schema-form-DEvdni_r.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BsgffzV4.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-t6v8Dwb8.js +0 -2
- package/dist/gateway/static/root/assets/settings-form-section-BoYYZmJG.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-ClIthYF8.js +0 -3
- package/dist/gateway/static/root/assets/share-preview-page-Dd9et7KD.js +0 -2
- package/dist/gateway/static/root/assets/skills-page-DEXtxyfQ.js +0 -2
- package/dist/gateway/static/root/assets/theme-store-BZozwAeK.js +0 -1
- package/dist/gateway/static/root/assets/url-DQRqHuL-.js +0 -3
- package/dist/gateway/static/root/assets/vendor-codemirror-DYoKfS8f.js +0 -45
- package/dist/gateway/static/root/assets/voice-api-key-field-CNrKzQrf.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-EMZkzJNN.js +0 -18
- package/dist/src/agent/goals/checklist-user.d.ts +0 -24
- package/dist/src/agent/goals/checklist-user.js +0 -92
- package/dist/src/agent/goals/checklist-user.js.map +0 -1
- package/dist/src/agent/goals/goal-run-store.d.ts +0 -19
- package/dist/src/agent/goals/goal-run-store.js +0 -138
- package/dist/src/agent/goals/goal-run-store.js.map +0 -1
- package/dist/src/agent/goals/goal-run-types.d.ts +0 -28
- package/dist/src/agent/goals/goal-run-types.js +0 -6
- package/dist/src/agent/goals/goal-run-types.js.map +0 -1
- package/dist/src/agent/goals/patch-from-user-action.d.ts +0 -20
- package/dist/src/agent/goals/patch-from-user-action.js +0 -103
- package/dist/src/agent/goals/patch-from-user-action.js.map +0 -1
- /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
|
|
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 {
|
|
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,
|
|
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
|
|
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 {
|
|
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
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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":";;;;;;;;;aAGiE;aAGZ;AAOrD,MAAM,MAAM,aAAa,iBAAiB;AAC1C,MAAM,cAAc,IAAI,aAAa;AAErC,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,MAoBjC;CAChB,MAAM,EACJ,MACA,YACA,oBACA,SACA,aACA,4BACA,QACA,wBACA,QACA,yBACA,wBACE;AAEJ,KAAI,2BAA4B;AAChC,KAAI,WAAW,YAAa;AAG5B,KAAI,CAAC,MADc,KAAK,mBAAmB,WAAW,CAC3C;CAEX,MAAM,OAAO,YAAY,oBAAoB,WAAW;AACxD,KAAI,CAAC,QAAQ,KAAK,WAAW,SAAU;CAEvC,MAAM,QAA6B;EACjC,MAAM,KAAK;EACX,QAAQ;EACR,WAAW,KAAK;EAChB,UAAU,KAAK;EACf,WAAW,KAAK;EAChB,YAAY,KAAK;EACjB,YAAY,KAAK;EACjB,eAAe,KAAK;EACpB,YAAY,KAAK,UAAU,SAAS,IAAI,OAAO,KAAA;EAC/C,UAAU,KAAK;EACf,WAAW,KAAK,UAAU,KAAK,QAAQ;GACrC,MAAM,GAAG;GACT,QAAQ,GAAG;GACX,SAAS,GAAG;GACZ,SAAS,GAAG;GACZ,aAAa,GAAG;GAChB,UAAU,GAAG;GACd,EAAE;EACJ;CAED,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;AAEF,KAAI,SAAS,UAAU;EACrB,MAAM,KAAK,SAAS;EACpB,MAAM,4BAA4B,SAAS,+BACvC,KAAK,UAAU,KAAK,UAAU,QAAQ,GAAG,CAC1C,QAAQ,OAAqB,OAAO,OAAO,YAAY,GAAG,SAAS,EAAE;AACxE,MAAI;GACF,MAAM,cAAc,YAAY,kBAAkB;IAChD,QAAQ,KAAK;IACb;IACA,QAAQ;IACR,QAAQ,GAAG,WAAW,SAClB,SACA,SAAS,YAAY,YACnB,YACA,SAAS,YAAY,gBACnB,gBACA,GAAG,WAAW,WACZ,WACA;IACV,WAAW,GAAG;IACd,UAAU,GAAG;IACb,QAAQ,GAAG,gBAAgB,SAAS;IACpC,YAAY,SAAS,sBAAsB,KAAA;IAC3C,kBAAkB;IAClB,SAAS,SAAS,YAAY,SAC1B,SACA,SAAS,YAAY,cACnB,cACA,SAAS,YAAY,YACnB,YACA,SAAS,YAAY,gBACnB,gBACA;IACV,YAAY,SAAS;IACrB,iBAAiB,SAAS;IAC1B,cAAc,SAAS;IACvB;IACA,WAAW,GAAG,WAAW,KAAK,QAAQ;KACpC,MAAM,GAAG;KACT,QAAQ,GAAG;KACX,SAAS,GAAG;KACZ,SAAS,GAAG;KACZ,aAAa,GAAG;KAChB,iBAAiB,GAAG;KACrB,EAAE;IACJ,CAAC;AACF,OAAI,eAAe,YAAY,WAAW,KAAK,OAC7C,uBAAsB;IACpB,QAAQ,KAAK;IACb;IACA,gBAAgB,KAAK;IACrB,QAAQ,YAAY;IACpB,MAAM;IACP,CAAC;WAEG,KAAK;AACZ,OAAI,KACF;IAAE;IAAK;IAAY,QAAQ,KAAK;IAAI,EACpC,+CAA+C,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAChG;;;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,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 {
|
|
80
|
+
export { applyJudgeChecklistUpdates, defaultMaxTurns, mergeDecomposedChecklistItems, renderChecklistNumbered, renderChecklistPlain };
|
|
176
81
|
|
|
177
82
|
//# sourceMappingURL=state.js.map
|