@xopcai/xopc 0.0.359 → 0.0.361
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/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-CnmHVy1D.js → activity-store-tpFInIoh.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-D-yhlYSG.js → agent-avatar-dicebear-DUhFW_Go.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-BNILmgey.js +1 -0
- package/dist/gateway/static/root/assets/agent-plugin-dialog-CnWci4JJ.js +1 -0
- package/dist/gateway/static/root/assets/agents-CKS5LUUs.js +66 -0
- package/dist/gateway/static/root/assets/{agents-admin-api-BtnYiq7O.js → agents-admin-api-CiAjB2iQ.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-CiSdkzuX.js → app-management-settings-panel-DEig00YU.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-SdlCHKg8.js → appearance-settings-CccnRRrL.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-ntyBe6mP.js → apps-page-CkT6UNZW.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-DZCN9m71.js → archive-plugin-CIlmZBe5.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-DU0R5C65.js → automations-page-8kZugDcf.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-3V54ShL0.js +7 -0
- package/dist/gateway/static/root/assets/{binary-plugins-U63xxRgh.js → binary-plugins-BuQiee_b.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CLejMPkV.js → block-editor-BFFRbsKX.js} +3 -3
- package/dist/gateway/static/root/assets/{browser-automation-inputs-MmkUGn9W.js → browser-automation-inputs-CWujpdCx.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automations-page-BjGswNM0.js → browser-automations-page-HVXiBKXE.js} +2 -2
- package/dist/gateway/static/root/assets/browser-settings-page-DpxAXNvM.js +3 -0
- package/dist/gateway/static/root/assets/{capabilities-BXG_5wIg.js → capabilities-CngwB2JU.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-Bigu28Z6.js → capabilities-RMlKKfGF.js} +1 -1
- package/dist/gateway/static/root/assets/capabilities-page-BBi4ef3u.js +2 -0
- package/dist/gateway/static/root/assets/capabilities-settings-panel-IxszGl-Q.js +8 -0
- package/dist/gateway/static/root/assets/{capability-header-actions-B0Xiav_-.js → capability-header-actions-BLOIJvIZ.js} +1 -1
- package/dist/gateway/static/root/assets/channels-Ced5nFBc.js +1 -0
- package/dist/gateway/static/root/assets/{chat-terminal-dock-C9pMFB6k.js → chat-terminal-dock-BskUzDCS.js} +2 -2
- package/dist/gateway/static/root/assets/computer-settings-page-De-pjlvn.js +1 -0
- package/dist/gateway/static/root/assets/{connector-service-page-OyQKwHNr.js → connector-service-page-Qc1mVfp9.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-CPqeY1x5.js +2 -0
- package/dist/gateway/static/root/assets/{constants-Co2_smKQ.js → constants-Dy8Gw0sF.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-DxGsweV_.js → date-picker-7ppMIGfQ.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-D9ZfAJwn.js → dependency-picker-DfYC22si.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-DFgK1z5i.js → desktop-pet-GKEfqHDF.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-CyFW0raW.js → desktop-pet-settings-qoFZBKe9.js} +1 -1
- package/dist/gateway/static/root/assets/{device-pairing-wizard-C6Co5dT3.js → device-pairing-wizard-D8sTDd5s.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-2nrl6Exh.js → directory-picker-path-field-BC87CZa2.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-BodxNAys.js → extension-debug-page-VxCq29jC.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DMb2YFlb.js → extension-page-DypBVBTt.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-provider-aigS3RJu.js → extension-provider-wlvxPese.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-D3hvXtxi.js → extension-settings-page-DzzkBN9y.js} +1 -1
- package/dist/gateway/static/root/assets/{fallback-models-DsXySQVF.js → fallback-models-s4qTRcPJ.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-EZxaKXdC.js → gateway-config-swr-ZM72jovc.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-realtime-DBRa17u3.js → gateway-realtime-B-hrykag.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-realtime-store-B6B1fw_K.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-settings-CubM1m6Z.js → gateway-settings--M7ZH_37.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-Wtxq_y2f.js → gateway-startup-retry-DjWuTj8B.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-KFs5suD1.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-Bnl0CH4n.js → image-generation-api-C9cwrqCr.js} +1 -1
- package/dist/gateway/static/root/assets/{imports-page-Czzsa_Eu.js → imports-page-BKy0ImXk.js} +1 -1
- package/dist/gateway/static/root/assets/{index-DUgsBdV3.css → index-B7AHDHSO.css} +1 -1
- package/dist/gateway/static/root/assets/index-C0JT9Ja4.js +106 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-DqsFlXlp.js → keyboard-shortcuts-settings-CexiL-Ey.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page-BcDFXc1k.js → local-app-workbench-page-CcU1OLWQ.js} +1 -1
- package/dist/gateway/static/root/assets/{local-apps-page-BaxqXA1-.js → local-apps-page-BcLijQx4.js} +1 -1
- package/dist/gateway/static/root/assets/{local-session-drafts-CeHhcudO.js → local-session-drafts-C7QjBMNp.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-ChN_vjs2.js → locale-store-5sV3dDRG.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-DmJjZ0Uk.js → logs-page-48nrZNQe.js} +2 -2
- package/dist/gateway/static/root/assets/management-settings-B_gzl_Vh.js +1 -0
- package/dist/gateway/static/root/assets/{markdown-view-DKlJx4eo.js → markdown-view-V0f5NW7D.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-JWzrPQwt.js → media-plugins-_obxSZmT.js} +1 -1
- package/dist/gateway/static/root/assets/{messages-CnM6Qfr7.js → messages-CaURu8bb.js} +2 -2
- package/dist/gateway/static/root/assets/models-hub-cache-Cs3E5pEA.js +1 -0
- package/dist/gateway/static/root/assets/{note-detail-panel-BLvVlQG8.js → note-detail-panel-B9AeX98W.js} +3 -3
- package/dist/gateway/static/root/assets/{notes-api-D8nvWMMC.js → notes-api-CBnMq6Nc.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-CKTTfxw-.js +8 -0
- package/dist/gateway/static/root/assets/{oauth-api-BXn1a9qx.js → oauth-api-Bu2RoLF2.js} +1 -1
- package/dist/gateway/static/root/assets/{page-context-capture-button-gL3453SU.js → page-context-capture-button-BsxBAWD_.js} +1 -1
- package/dist/gateway/static/root/assets/personal-page-Cfl1FR3i.js +1 -0
- package/dist/gateway/static/root/assets/{product-open-page-Dw8JPizo.js → product-open-page-D1ARqS3r.js} +1 -1
- package/dist/gateway/static/root/assets/{project-detail-page-Zg4KZ0vK.js → project-detail-page-Cro1OE8P.js} +1 -1
- package/dist/gateway/static/root/assets/projects-page-CdEmmBCz.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-BM_81rLe.js → registry-api-j1rNFkP2.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-C9_ea_4p.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-BLNXzyeh.js → runtime-tools-settings-panel-DtmQbC72.js} +1 -1
- package/dist/gateway/static/root/assets/{scenes-page-D868Zuj9.js → scenes-page-DeFdMf2q.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-5z33VTce.js → schema-form-ByEHHW6n.js} +1 -1
- package/dist/gateway/static/root/assets/{send-session-input-OaBPDJ9E.js → send-session-input-CO_vUCb8.js} +1 -1
- package/dist/gateway/static/root/assets/{session-api-UkGomZfv.js → session-api-CYPGi01d.js} +1 -1
- package/dist/gateway/static/root/assets/session-manager-BdJThQQ6.js +16 -0
- package/dist/gateway/static/root/assets/sessions-page-CV0JlaXS.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-D9sW0hKa.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-BG_dOYMq.js → settings-page-CHKsZFAN.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-DNj1hD_H.js → setup-status-panel-CC58OVOe.js} +1 -1
- package/dist/gateway/static/root/assets/{share-link-dialog-BvSRHs1P.js → share-link-dialog-ZOdnHkmb.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-M_rAQR60.js → share-preview-page-BPDWUuH_.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-api-DwqLga5H.js → shares-api-T5gR8yqz.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-DaXvdH8c.js +1 -0
- package/dist/gateway/static/root/assets/{skill-api-BBaKs-Xx.js → skill-api-CHCLMcfO.js} +1 -1
- package/dist/gateway/static/root/assets/{skill-reload-api-C1hzIawD.js → skill-reload-api-C-RoiUJi.js} +1 -1
- package/dist/gateway/static/root/assets/skills-page-a9UQQnqn.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-DKjsZo49.js → system-settings-panel-Dho_dlBS.js} +1 -1
- package/dist/gateway/static/root/assets/{task-detail-page-DSvaiKGb.js → task-detail-page-B5JyH4z7.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-DTYk7Gll.js → theme-store-CEl74p7l.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-DR8Qu6R_.js → tunnel-api-BDqCyf8G.js} +1 -1
- package/dist/gateway/static/root/assets/{usage-page-CAIqAduR.js → usage-page-DKwKfszc.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-R3hEHQQq.js → use-autosave-D09eZTLp.js} +1 -1
- package/dist/gateway/static/root/assets/{use-composer-attachments-CUaywGe0.js → use-composer-attachments-CkvJM8Km.js} +1 -1
- package/dist/gateway/static/root/assets/{use-file-preview-expanded-D809I8ur.js → use-file-preview-expanded-J3HnG8OH.js} +2 -2
- package/dist/gateway/static/root/assets/user-model-page-BsgADrGL.js +2 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-C-AF-IcO.js → voice-api-key-field-DH-to9Rd.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-CxGsCDoW.js → voice-config-api-CmCfVy3H.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-wGFcle2p.js → work-discovery-overlay-x1vZDBhu.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-CewS2IbN.js → workflow-run-setup-panel-DGatvmK1.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-DgNy6mBQ.js +6 -0
- package/dist/gateway/static/root/assets/{workspace-api-BtXzxf_w.js → workspace-api-DzPw92Kx.js} +2 -2
- package/dist/gateway/static/root/index.html +29 -30
- package/dist/package.js +1 -1
- package/dist/packages/gateway-contract/src/index.js +2 -0
- package/dist/packages/gateway-contract/src/task-result-delivery.js +30 -0
- package/dist/src/agent/context/workspace-templates/SOUL.md +2 -0
- package/dist/src/agent/embedded/run-for-session.js +70 -4
- package/dist/src/agent/external-tools/gateway-tools.js +41 -1
- package/dist/src/agent/inbound/attachment-pipeline.js +13 -0
- package/dist/src/agent/memory/compaction-policy.d.ts +4 -0
- package/dist/src/agent/memory/compaction-policy.js +3 -0
- package/dist/src/agent/memory/idle-compaction-scheduler.d.ts +28 -0
- package/dist/src/agent/memory/idle-compaction-scheduler.js +127 -0
- package/dist/src/agent/prompt/sections/behavior.js +4 -1
- package/dist/src/agent/prompt/sections/memory-skills.js +2 -0
- package/dist/src/agent/service/process-direct-one-shot.js +1 -0
- package/dist/src/agent/service/process-direct-streaming.js +1 -0
- package/dist/src/agent/service.js +1 -0
- package/dist/src/agent/session/session-config-service.js +11 -3
- package/dist/src/agent/tools/delegation-policy.js +1 -0
- package/dist/src/agent/tools/factory.js +48 -8
- package/dist/src/agent/tools/index.d.ts +1 -0
- package/dist/src/agent/tools/index.js +2 -1
- package/dist/src/agent/tools/media-read-tool.d.ts +5 -1
- package/dist/src/agent/tools/media-read-tool.js +44 -5
- package/dist/src/agent/tools/personal-preference-tool.js +11 -0
- package/dist/src/agent/tools/personal-read-tool.d.ts +3 -0
- package/dist/src/agent/tools/personal-read-tool.js +155 -0
- package/dist/src/agent/tools/personal-request-result-tool.d.ts +22 -0
- package/dist/src/agent/tools/personal-request-result-tool.js +84 -0
- package/dist/src/agent/tools/personal-request-tool.d.ts +3 -0
- package/dist/src/agent/tools/personal-request-tool.js +100 -0
- package/dist/src/agent/tools/personal-task-tool.d.ts +6 -0
- package/dist/src/agent/tools/personal-task-tool.js +13 -11
- package/dist/src/agent/tools/read.d.ts +3 -0
- package/dist/src/agent/tools/read.js +26 -8
- package/dist/src/agent/tools/session-search-tool.d.ts +1 -0
- package/dist/src/agent/tools/session-search-tool.js +39 -5
- package/dist/src/agent/tools/tool-media.js +2 -3
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/templates.js +4 -0
- package/dist/src/config/schema.d.ts +10 -0
- package/dist/src/connectors/connection-recovery-service.d.ts +2 -0
- package/dist/src/connectors/connection-recovery-service.js +23 -5
- package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +10 -0
- package/dist/src/gateway/hono/routes/media.js +4 -3
- package/dist/src/gateway/hono/routes/personal-agent.js +69 -1
- package/dist/src/gateway/hono/routes/sessions.js +1 -1
- package/dist/src/gateway/hono/routes/voice.js +1 -1
- package/dist/src/gateway/media-access.js +2 -2
- package/dist/src/gateway/service/agent-runner.js +1 -0
- package/dist/src/gateway/service/session-command-service.js +1 -1
- package/dist/src/gateway/service/session-input-coordinator.d.ts +1 -0
- package/dist/src/gateway/service/session-input-coordinator.js +2 -0
- package/dist/src/gateway/service.d.ts +3 -0
- package/dist/src/gateway/service.js +45 -4
- package/dist/src/media/index.js +2 -2
- package/dist/src/media/session-references.d.ts +2 -0
- package/dist/src/media/session-references.js +22 -2
- package/dist/src/media/store.d.ts +1 -0
- package/dist/src/media/store.js +7 -2
- package/dist/src/personal-agent/capability-service.d.ts +14 -0
- package/dist/src/personal-agent/capability-service.js +63 -0
- package/dist/src/personal-agent/communication.d.ts +4 -0
- package/dist/src/personal-agent/communication.js +24 -0
- package/dist/src/personal-agent/model-config.d.ts +5 -0
- package/dist/src/personal-agent/model-config.js +59 -0
- package/dist/src/personal-agent/policy.d.ts +1 -1
- package/dist/src/personal-agent/policy.js +6 -0
- package/dist/src/personal-agent/repository.d.ts +1 -0
- package/dist/src/personal-agent/repository.js +3 -1
- package/dist/src/personal-agent/request-delivery.d.ts +4 -0
- package/dist/src/personal-agent/request-delivery.js +159 -0
- package/dist/src/personal-agent/request-repository.d.ts +33 -0
- package/dist/src/personal-agent/request-repository.js +71 -0
- package/dist/src/personal-agent/request-result.d.ts +21 -0
- package/dist/src/personal-agent/request-result.js +45 -0
- package/dist/src/personal-agent/request-service.d.ts +18 -0
- package/dist/src/personal-agent/request-service.js +308 -0
- package/dist/src/personal-agent/service.js +32 -7
- package/dist/src/session/client-history.d.ts +2 -1
- package/dist/src/session/client-history.js +40 -0
- package/dist/src/session/compact-history.js +9 -5
- package/dist/src/session/config-store.js +2 -1
- package/dist/src/session/session-context-for-llm.js +55 -0
- package/dist/src/session/store.d.ts +12 -1
- package/dist/src/session/store.js +35 -0
- package/dist/src/session/types.d.ts +2 -0
- package/dist/src/storage/sqlite/connection-wait-repository.d.ts +5 -1
- package/dist/src/storage/sqlite/connection-wait-repository.js +38 -8
- package/dist/src/storage/sqlite/migrations/231_task_result_deliveries.sql +32 -0
- package/dist/src/storage/sqlite/migrations/232_personal_requests.sql +28 -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/schema.js +1 -1
- package/dist/src/storage/sqlite/session-repository.js +33 -0
- package/dist/src/storage/sqlite/transcript-repository.d.ts +4 -1
- package/dist/src/storage/sqlite/transcript-repository.js +15 -1
- package/dist/src/tasks/task-application-service.d.ts +1 -0
- package/dist/src/tasks/task-application-service.js +7 -0
- package/dist/src/tasks/task-context-assembler.js +1 -0
- package/dist/src/tasks/task-main-update-decision-service.js +1 -1
- package/dist/src/tasks/task-main-update-delivery.js +32 -1
- package/dist/src/tasks/task-result-delivery-repository.d.ts +18 -0
- package/dist/src/tasks/task-result-delivery-repository.js +144 -0
- package/dist/src/tasks/task-result-delivery-service.d.ts +4 -0
- package/dist/src/tasks/task-result-delivery-service.js +128 -0
- package/dist/src/tasks/task-run-coordinator.js +6 -1
- package/dist/src/tasks/task-run-dispatcher.d.ts +1 -0
- package/dist/src/tasks/task-run-dispatcher.js +22 -3
- package/dist/src/user-context/config.d.ts +48 -0
- package/dist/src/user-context/config.js +23 -3
- package/dist/src/voice/realtime/runtime.js +1 -1
- package/package.json +3 -3
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CYq-3pbE.js +0 -1
- package/dist/gateway/static/root/assets/agent-plugin-dialog-Cx3UbhqT.js +0 -1
- package/dist/gateway/static/root/assets/agents-Ce9uvui7.js +0 -66
- package/dist/gateway/static/root/assets/automations-workspace-BaHJml4R.js +0 -7
- package/dist/gateway/static/root/assets/browser-settings-page-DBcYssNQ.js +0 -3
- package/dist/gateway/static/root/assets/capabilities-page-CsTpcrPP.js +0 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-BXlVwnMr.js +0 -8
- package/dist/gateway/static/root/assets/channels-TPqwcbZ4.js +0 -1
- package/dist/gateway/static/root/assets/computer-settings-page-BJOn14Ow.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-DBWH5bVr.js +0 -2
- package/dist/gateway/static/root/assets/gateway-realtime-store-7glMlD2l.js +0 -1
- package/dist/gateway/static/root/assets/home-page-CQ9y_LMT.js +0 -1
- package/dist/gateway/static/root/assets/index-DUU_2HF0.js +0 -106
- package/dist/gateway/static/root/assets/management-settings-1O7zsu4t.js +0 -1
- package/dist/gateway/static/root/assets/model-display-name-DXhO9rcM.js +0 -1
- package/dist/gateway/static/root/assets/models-hub-cache-DnIOzcvn.js +0 -1
- package/dist/gateway/static/root/assets/notes-page-AWU_G61i.js +0 -8
- package/dist/gateway/static/root/assets/personal-page-BPy5m3QR.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-B33uj1lz.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BZoUVzgS.js +0 -1
- package/dist/gateway/static/root/assets/session-manager-BK5IvdGz.js +0 -16
- package/dist/gateway/static/root/assets/sessions-page-Du7ueBFc.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CaxCsIIZ.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-Cr_Ut6FE.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-DU7fV5pc.js +0 -2
- package/dist/gateway/static/root/assets/user-model-page-C--t6SLp.js +0 -2
- package/dist/gateway/static/root/assets/workflows-page-CxfsWFL5.js +0 -6
|
@@ -3,6 +3,7 @@ import { getSqliteDatabase, init_transaction, runSqliteWriteTransaction } from "
|
|
|
3
3
|
import { validateConversationId, validateTranscriptId } from "../../../packages/gateway-contract/src/conversation-identity.js";
|
|
4
4
|
import { init_src } from "../../../packages/gateway-contract/src/index.js";
|
|
5
5
|
import { init_session_instance_repository, readCurrentTranscriptId } from "./session-instance-repository.js";
|
|
6
|
+
import { TaskRunRepository, init_task_run_repository } from "../../tasks/task-run-repository.js";
|
|
6
7
|
import { buildDefaultSessionMetadata, init_session_metadata } from "./session-metadata.js";
|
|
7
8
|
import { init_timestamps, optionalTimestampToMs } from "./timestamps.js";
|
|
8
9
|
import { buildGlobalSessionStats, init_row_mappers, metadataToSessionInsert, sessionRowToMetadata } from "./row-mappers.js";
|
|
@@ -311,6 +312,37 @@ function deleteSessionRecord(conversationId) {
|
|
|
311
312
|
db.prepare(`UPDATE transcripts SET status = 'archived', archive_reason = 'delete', archived_at = ?
|
|
312
313
|
WHERE transcript_id = ?`).run(now, existing.active_transcript_id);
|
|
313
314
|
cancelConnectionObjective(conversationId);
|
|
315
|
+
if (db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'personal_requests'").get()) {
|
|
316
|
+
const requests = db.prepare("SELECT task_id FROM personal_requests WHERE conversation_id = ? AND task_id IS NOT NULL").all(conversationId);
|
|
317
|
+
const runs = new TaskRunRepository();
|
|
318
|
+
for (const request of requests) {
|
|
319
|
+
const run = runs.getActiveRoot(request.task_id);
|
|
320
|
+
if (!run) continue;
|
|
321
|
+
for (const wait of runs.listActiveWaits(request.task_id)) runs.resolveWait({
|
|
322
|
+
waitId: wait.id,
|
|
323
|
+
actor: { kind: "user" },
|
|
324
|
+
resolution: { cancelled: true }
|
|
325
|
+
});
|
|
326
|
+
runs.finalize({
|
|
327
|
+
runId: run.id,
|
|
328
|
+
expectedVersion: run.version,
|
|
329
|
+
actor: { kind: "user" },
|
|
330
|
+
receipt: {
|
|
331
|
+
status: "cancelled",
|
|
332
|
+
summary: "Originating Personal conversation deleted",
|
|
333
|
+
changes: [],
|
|
334
|
+
evidence: [],
|
|
335
|
+
verification: {
|
|
336
|
+
status: "unverified",
|
|
337
|
+
checks: []
|
|
338
|
+
},
|
|
339
|
+
remainingWork: [],
|
|
340
|
+
needsUser: false,
|
|
341
|
+
completionVerdict: "not_achieved"
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
}
|
|
314
346
|
db.prepare(`DELETE FROM sessions WHERE conversation_id = ?`).run(conversationId);
|
|
315
347
|
return true;
|
|
316
348
|
});
|
|
@@ -334,6 +366,7 @@ function resolveSessionAgentId(conversationId) {
|
|
|
334
366
|
}
|
|
335
367
|
var init_session_repository = __esmMin((() => {
|
|
336
368
|
init_connection_wait_repository();
|
|
369
|
+
init_task_run_repository();
|
|
337
370
|
init_src();
|
|
338
371
|
init_changes();
|
|
339
372
|
init_session_metadata();
|
|
@@ -10,6 +10,7 @@ export interface TranscriptSourceEntry {
|
|
|
10
10
|
row: TranscriptStoredRow;
|
|
11
11
|
}
|
|
12
12
|
export interface CompactionSourceSnapshot {
|
|
13
|
+
fingerprint?: string;
|
|
13
14
|
transcriptId: string;
|
|
14
15
|
lastSeq: number;
|
|
15
16
|
entries: TranscriptSourceEntry[];
|
|
@@ -25,7 +26,9 @@ export declare function appendTranscriptEntry(conversationId: string, row: Trans
|
|
|
25
26
|
transcriptId?: string;
|
|
26
27
|
tokenDelta?: number;
|
|
27
28
|
}): TranscriptEntryRow;
|
|
28
|
-
export declare function appendCompactionBoundaryIfUnchanged(conversationId: string, expected: Pick<CompactionSourceSnapshot, 'transcriptId' | 'lastSeq'
|
|
29
|
+
export declare function appendCompactionBoundaryIfUnchanged(conversationId: string, expected: Pick<CompactionSourceSnapshot, 'transcriptId' | 'lastSeq'> & {
|
|
30
|
+
fingerprint?: string;
|
|
31
|
+
}, row: Omit<XopcTranscriptCompactionEntry, 'baseSeq'>): TranscriptEntryRow | null;
|
|
29
32
|
export declare function loadCompactionSourceSnapshot(conversationId: string): CompactionSourceSnapshot | null;
|
|
30
33
|
export declare function searchSessionTranscript(conversationId: string, query: string, options?: {
|
|
31
34
|
limit?: number;
|
|
@@ -5,7 +5,7 @@ import { buildSessionContextForLlm, init_session_context_for_llm, isRuntimeOnlyT
|
|
|
5
5
|
import { classifyStoredRow, estimateTokensFromMessages, extractFtsContent, init_row_mappers, transcriptEntryRowToStoredRow } from "./row-mappers.js";
|
|
6
6
|
import { escapeFts5Query, init_fts } from "./fts.js";
|
|
7
7
|
import { getCurrentTranscriptId, init_session_repository } from "./session-repository.js";
|
|
8
|
-
import { randomUUID } from "node:crypto";
|
|
8
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
9
9
|
//#region src/storage/sqlite/transcript-repository.ts
|
|
10
10
|
function nextSeq(db, transcriptId) {
|
|
11
11
|
return (db.prepare(`SELECT COALESCE(MAX(seq), 0) AS max_seq FROM transcript_entries WHERE transcript_id = ?`).get(transcriptId).max_seq ?? 0) + 1;
|
|
@@ -100,12 +100,25 @@ function appendTranscriptEntry(conversationId, row, opts) {
|
|
|
100
100
|
return inserted;
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
|
+
function compactionRowsFingerprint(rows) {
|
|
104
|
+
const hash = createHash("sha256");
|
|
105
|
+
for (const row of rows) hash.update(JSON.stringify([
|
|
106
|
+
row.entry_id,
|
|
107
|
+
row.seq,
|
|
108
|
+
row.payload_json,
|
|
109
|
+
row.created_at
|
|
110
|
+
]));
|
|
111
|
+
return hash.digest("hex");
|
|
112
|
+
}
|
|
103
113
|
function appendCompactionBoundaryIfUnchanged(conversationId, expected, row) {
|
|
104
114
|
return runSqliteWriteTransaction((db) => {
|
|
105
115
|
const transcriptId = readCurrentTranscriptId(db, conversationId);
|
|
106
116
|
if (!transcriptId) throw new Error(`Session not found: ${conversationId}`);
|
|
107
117
|
if (transcriptId !== expected.transcriptId) return null;
|
|
108
118
|
if (nextSeq(db, transcriptId) - 1 !== expected.lastSeq) return null;
|
|
119
|
+
if (expected.fingerprint) {
|
|
120
|
+
if (compactionRowsFingerprint(db.prepare("SELECT entry_id, seq, payload_json, created_at FROM transcript_entries WHERE transcript_id = ? ORDER BY seq ASC").all(transcriptId)) !== expected.fingerprint) return null;
|
|
121
|
+
}
|
|
109
122
|
const boundary = {
|
|
110
123
|
...row,
|
|
111
124
|
baseSeq: expected.lastSeq
|
|
@@ -138,6 +151,7 @@ function loadCompactionSourceSnapshot(conversationId) {
|
|
|
138
151
|
return {
|
|
139
152
|
transcriptId,
|
|
140
153
|
lastSeq: rows.at(-1)?.seq ?? 0,
|
|
154
|
+
fingerprint: compactionRowsFingerprint(rows),
|
|
141
155
|
entries: rows.map((entry) => ({
|
|
142
156
|
entryId: entry.entry_id,
|
|
143
157
|
seq: entry.seq,
|
|
@@ -10,6 +10,7 @@ import { TaskContextRepository } from "./task-context-repository.js";
|
|
|
10
10
|
import { TaskDependencyService } from "./task-dependency-service.js";
|
|
11
11
|
import { TaskCriterionReviewRepository } from "./task-criterion-review-repository.js";
|
|
12
12
|
import { TaskCollaborationRepository } from "./task-collaboration-repository.js";
|
|
13
|
+
import { TaskResultDeliveryRepository } from "./task-result-delivery-repository.js";
|
|
13
14
|
import { createHash, randomUUID } from "node:crypto";
|
|
14
15
|
//#region src/tasks/task-application-service.ts
|
|
15
16
|
init_src();
|
|
@@ -97,6 +98,11 @@ var TaskApplicationService = class {
|
|
|
97
98
|
if (input.originConversationId) {
|
|
98
99
|
if (db.prepare(`INSERT INTO task_origin_links (task_id, conversation_id, created_at)
|
|
99
100
|
SELECT ?, conversation_id, ? FROM sessions WHERE conversation_id = ?`).run(task.id, task.createdAt, input.originConversationId).changes !== 1) throw new Error("Task origin conversation not found");
|
|
101
|
+
db.prepare(`UPDATE task_origin_links SET
|
|
102
|
+
origin_transcript_id = (SELECT active_transcript_id FROM sessions WHERE conversation_id = ?),
|
|
103
|
+
request_input_id = (SELECT id FROM session_inputs WHERE conversation_id = ?
|
|
104
|
+
AND status = 'running' ORDER BY created_at_ms DESC LIMIT 1)
|
|
105
|
+
WHERE task_id = ?`).run(input.originConversationId, input.originConversationId, task.id);
|
|
100
106
|
db.prepare(`INSERT INTO task_main_agent_links (task_id, agent_id, origin_conversation_id, created_at)
|
|
101
107
|
SELECT ?, agent_id, conversation_id, ? FROM sessions WHERE conversation_id = ?`).run(task.id, task.createdAt, input.originConversationId);
|
|
102
108
|
}
|
|
@@ -491,6 +497,7 @@ var TaskApplicationService = class {
|
|
|
491
497
|
body: input.receipt.summary || (input.receipt.status === "succeeded" ? "TaskRun completed" : "TaskRun failed"),
|
|
492
498
|
idempotencyKey: `task-run-receipt:${run.id}`
|
|
493
499
|
});
|
|
500
|
+
if (input.receipt.status === "succeeded" || input.receipt.status === "failed") new TaskResultDeliveryRepository().enqueue(run.id, input.receipt.summary, input.receipt.status, input.resultText);
|
|
494
501
|
if (input.receipt.status !== "succeeded") {
|
|
495
502
|
const model = this.#projector.project(task);
|
|
496
503
|
if (!input.suppressAttention) enqueueTaskAttentionRequiredEvent(db, {
|
|
@@ -145,6 +145,7 @@ function buildTaskExecutionDirective(conversationId) {
|
|
|
145
145
|
handoffPayload ? `Handoff snapshot: ${handoffPayload}` : "",
|
|
146
146
|
collaboration.length ? `Recent task collaboration:\n${collaboration.map((entry) => `- ${entry.sequence} ${entry.authorKind} ${entry.kind}: ${JSON.stringify(entry.body.slice(0, 1e3))}`).join("\n")}` : "",
|
|
147
147
|
"Report meaningful progress with xopc_use task collaboration_post. If blocked, post a question and stop this execution turn until answered.",
|
|
148
|
+
"For user-facing files, publish completed outputs with publish_artifacts before finishing. image_generate already publishes its images. Return structured artifact references rather than only local file paths. Published final outcomes are delivered automatically to the originating chat. Keep the final summary short and distinguish generated outputs from verified or accepted results.",
|
|
148
149
|
"Take safe in-scope steps and produce inspectable evidence. Do not claim completion without verification.",
|
|
149
150
|
"</xopc_task_execution>"
|
|
150
151
|
].filter(Boolean).join("\n");
|
|
@@ -3,8 +3,8 @@ import { TaskRunRepository, init_task_run_repository } from "./task-run-reposito
|
|
|
3
3
|
import { init_providers, resolveModel } from "../providers/index.js";
|
|
4
4
|
import { completeWithResolvedCredentials } from "../providers/model-call.js";
|
|
5
5
|
import { extractAssistantText, getAssistantMessageErrorReason, stripCodeFences } from "../providers/model-response.js";
|
|
6
|
-
import { TaskCollaborationRepository } from "./task-collaboration-repository.js";
|
|
7
6
|
import { getPersonalAgentByConversation } from "../personal-agent/repository.js";
|
|
7
|
+
import { TaskCollaborationRepository } from "./task-collaboration-repository.js";
|
|
8
8
|
//#region src/tasks/task-main-update-decision-service.ts
|
|
9
9
|
init_providers();
|
|
10
10
|
init_task_repository();
|
|
@@ -1,14 +1,41 @@
|
|
|
1
1
|
import { createLogger } from "../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
|
+
import { TaskRunRepository, init_task_run_repository } from "./task-run-repository.js";
|
|
4
|
+
import { init_request_repository, personalRequestForTask } from "../personal-agent/request-repository.js";
|
|
3
5
|
import { TaskCollaborationRepository } from "./task-collaboration-repository.js";
|
|
6
|
+
import { TaskResultDeliveryRepository } from "./task-result-delivery-repository.js";
|
|
4
7
|
//#region src/tasks/task-main-update-delivery.ts
|
|
5
8
|
init_logger();
|
|
9
|
+
init_task_run_repository();
|
|
10
|
+
init_request_repository();
|
|
6
11
|
const log = createLogger("TaskMainUpdateDelivery");
|
|
7
12
|
var TaskMainUpdateDelivery = class {
|
|
8
13
|
#entries = new TaskCollaborationRepository();
|
|
9
14
|
async drain(input, limit = 20) {
|
|
10
15
|
let delivered = 0;
|
|
11
16
|
for (const { entry, conversationId, decision, decisionReason } of this.#entries.pendingMainUpdates(limit)) {
|
|
17
|
+
if ([
|
|
18
|
+
"result",
|
|
19
|
+
"failure",
|
|
20
|
+
"progress"
|
|
21
|
+
].includes(entry.kind) && personalRequestForTask(entry.taskId)) {
|
|
22
|
+
this.#entries.markMainUpdateDelivered(entry.id);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const results = new TaskResultDeliveryRepository();
|
|
26
|
+
const isResult = entry.kind === "result" && entry.taskRunId;
|
|
27
|
+
if (isResult && results.hasForRun(entry.taskRunId)) {
|
|
28
|
+
this.#entries.markMainUpdateDelivered(entry.id);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (isResult && results.hasCapturedOutcome(entry.taskRunId) && [
|
|
32
|
+
"running",
|
|
33
|
+
"waiting",
|
|
34
|
+
"verifying"
|
|
35
|
+
].includes(new TaskRunRepository().get(entry.taskRunId)?.status ?? "")) {
|
|
36
|
+
this.#entries.deferMainUpdate(entry.id);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
12
39
|
if (!input.isAvailable(conversationId)) {
|
|
13
40
|
this.#entries.deferMainUpdate(entry.id);
|
|
14
41
|
continue;
|
|
@@ -31,6 +58,10 @@ var TaskMainUpdateDelivery = class {
|
|
|
31
58
|
entry
|
|
32
59
|
});
|
|
33
60
|
if (!decision) this.#entries.decideMainUpdate(entry.id, verdict.notify ? "notify" : "silent", verdict.reason);
|
|
61
|
+
if (isResult && results.hasForRun(entry.taskRunId)) {
|
|
62
|
+
this.#entries.markMainUpdateDelivered(entry.id);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
34
65
|
if (!verdict.notify) {
|
|
35
66
|
this.#entries.markMainUpdateDelivered(entry.id);
|
|
36
67
|
delivered += 1;
|
|
@@ -40,7 +71,7 @@ var TaskMainUpdateDelivery = class {
|
|
|
40
71
|
`A delegated Task has a new ${entry.kind} update. Task ID: ${entry.taskId}.`,
|
|
41
72
|
`Collaboration entry ID: ${entry.id}.`,
|
|
42
73
|
`Your private notification decision: ${JSON.stringify(verdict.reason)}.`,
|
|
43
|
-
"Read the Task and collaboration board with xopc_use. If this is a worker question, first answer it from the Task brief or conversation with personal_task(command=\"answer\", taskId, questionId, instruction) when available; ask the user only for a genuinely missing fact. For failures, inspect the actual blocker and try a suitable alternative within the user’s authorization before reporting an impasse. Then tell the user what matters in your own words. Keep the response proportionate to the update and recent conversation. Do not expose this internal trigger or repeat already reported details. If a result receipt is generic, use the board for the actual outcome. A finished TaskRun is not proof that the Task passed verification or was accepted; check its receipt and use precise status language. Do not ask the user to close a Task unless requested. Use tools without preliminary user-facing commentary, then give one concise reply."
|
|
74
|
+
"Read the Task and collaboration board with personal_task(command=\"get\", taskId) when available, otherwise xopc_use. If this is a worker question, first answer it from the Task brief or conversation with personal_task(command=\"answer\", taskId, questionId, instruction) when available; ask the user only for a genuinely missing fact. For failures, inspect the actual blocker and try a suitable alternative within the user’s authorization before reporting an impasse. Then tell the user what matters in your own words. Keep the response proportionate to the update and recent conversation. Do not expose this internal trigger or repeat already reported details. If a result receipt is generic, use the board for the actual outcome. A finished TaskRun is not proof that the Task passed verification or was accepted; check its receipt and use precise status language. Do not ask the user to close a Task unless requested. Use tools without preliminary user-facing commentary, then give one concise reply."
|
|
44
75
|
].join("\n");
|
|
45
76
|
if (await input.submitAndConfirm({
|
|
46
77
|
conversationId,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type TurnOutcome } from '@xopcai/gateway-contract';
|
|
2
|
+
export declare function onTaskResultQueued(listener: () => void): () => void;
|
|
3
|
+
export interface TaskResultDeliveryRow {
|
|
4
|
+
delivery_id: string;
|
|
5
|
+
payload_json: string;
|
|
6
|
+
status: 'pending' | 'delivered' | 'stale' | 'failed';
|
|
7
|
+
attempts: number;
|
|
8
|
+
message_entry_id: string | null;
|
|
9
|
+
}
|
|
10
|
+
export declare class TaskResultDeliveryRepository {
|
|
11
|
+
capture(runId: string, value: TurnOutcome): void;
|
|
12
|
+
/** Called inside the run completion transaction, after stale receipts are rejected. */
|
|
13
|
+
enqueue(runId: string, summary: string, status: 'succeeded' | 'failed', resultText?: string): boolean;
|
|
14
|
+
hasForRun(runId: string): boolean;
|
|
15
|
+
hasCapturedOutcome(runId: string): boolean;
|
|
16
|
+
pending(limit?: number): TaskResultDeliveryRow[];
|
|
17
|
+
retry(id: string, error: string): void;
|
|
18
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../utils/logger.js";
|
|
3
|
+
import { afterSqliteCommit, getSqliteDatabase, init_transaction, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
4
|
+
import { TurnOutcomeSchema } from "../../packages/gateway-contract/src/turn-outcome.js";
|
|
5
|
+
import { TaskResultDeliverySchema } from "../../packages/gateway-contract/src/task-result-delivery.js";
|
|
6
|
+
import { init_src } from "../../packages/gateway-contract/src/index.js";
|
|
7
|
+
import { TaskRunRepository, init_task_run_repository } from "./task-run-repository.js";
|
|
8
|
+
import { init_request_repository, personalRequestForTask } from "../personal-agent/request-repository.js";
|
|
9
|
+
import { TaskConversationRepository } from "./task-conversation-repository.js";
|
|
10
|
+
import { TaskCollaborationRepository } from "./task-collaboration-repository.js";
|
|
11
|
+
import { randomUUID } from "node:crypto";
|
|
12
|
+
//#region src/tasks/task-result-delivery-repository.ts
|
|
13
|
+
init_src();
|
|
14
|
+
init_transaction();
|
|
15
|
+
init_task_run_repository();
|
|
16
|
+
init_logger();
|
|
17
|
+
init_request_repository();
|
|
18
|
+
const log = createLogger("TaskResultDelivery");
|
|
19
|
+
const queuedListeners = /* @__PURE__ */ new Set();
|
|
20
|
+
function onTaskResultQueued(listener) {
|
|
21
|
+
queuedListeners.add(listener);
|
|
22
|
+
return () => {
|
|
23
|
+
queuedListeners.delete(listener);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
var TaskResultDeliveryRepository = class {
|
|
27
|
+
capture(runId, value) {
|
|
28
|
+
const outcome = TurnOutcomeSchema.parse({
|
|
29
|
+
...value,
|
|
30
|
+
evidence: [],
|
|
31
|
+
changeSet: void 0,
|
|
32
|
+
summary: value.summary?.slice(0, 2e3)
|
|
33
|
+
});
|
|
34
|
+
if (outcome.deliverables.length > 50 || JSON.stringify(outcome).length > 256e3) throw new Error("Task outcome exceeds delivery limits");
|
|
35
|
+
const run = new TaskRunRepository().get(runId);
|
|
36
|
+
if (!run || ![
|
|
37
|
+
"running",
|
|
38
|
+
"waiting",
|
|
39
|
+
"verifying"
|
|
40
|
+
].includes(run.status)) return;
|
|
41
|
+
const state = new TaskConversationRepository().getState(run.taskId);
|
|
42
|
+
if (!state || state.activeConversationId !== run.conversationId) return;
|
|
43
|
+
getSqliteDatabase().prepare(`INSERT INTO task_run_outcomes
|
|
44
|
+
(task_run_id, outcome_id, assignment_epoch, outcome_json, created_at)
|
|
45
|
+
VALUES (?, ?, ?, ?, ?) ON CONFLICT(task_run_id, outcome_id) DO NOTHING`).run(runId, outcome.outcomeId, state.assignmentEpoch, JSON.stringify(outcome), Date.now());
|
|
46
|
+
}
|
|
47
|
+
/** Called inside the run completion transaction, after stale receipts are rejected. */
|
|
48
|
+
enqueue(runId, summary, status, resultText) {
|
|
49
|
+
const db = getSqliteDatabase();
|
|
50
|
+
const run = new TaskRunRepository().get(runId);
|
|
51
|
+
if (!run || run.parentRunId) return false;
|
|
52
|
+
const state = new TaskConversationRepository().getState(run.taskId);
|
|
53
|
+
if (!state || state.activeConversationId !== run.conversationId) return false;
|
|
54
|
+
const origin = db.prepare(`SELECT origin.*, task.title FROM task_origin_links origin
|
|
55
|
+
JOIN tasks task ON task.task_id = origin.task_id
|
|
56
|
+
WHERE origin.task_id = ?`).get(run.taskId);
|
|
57
|
+
if (!origin?.origin_transcript_id) return false;
|
|
58
|
+
const outcomes = db.prepare(`SELECT outcome_json FROM task_run_outcomes
|
|
59
|
+
WHERE task_run_id = ? AND assignment_epoch = ? ORDER BY created_at, rowid LIMIT 100`).all(runId, state.assignmentEpoch).map((row) => TurnOutcomeSchema.parse(JSON.parse(row.outcome_json)));
|
|
60
|
+
const latest = outcomes.at(-1);
|
|
61
|
+
if (!latest) return false;
|
|
62
|
+
const artifacts = /* @__PURE__ */ new Map();
|
|
63
|
+
for (const outcome of outcomes) for (const item of outcome.deliverables) artifacts.set(item.sourceFileId ?? item.artifactId, item);
|
|
64
|
+
const deliverables = [...artifacts.values()].slice(-50);
|
|
65
|
+
const text = resultText?.trim() && resultText.trim() !== "NO_REPLY" ? resultText.trim().slice(0, 8e3) : void 0;
|
|
66
|
+
if (!deliverables.length && (!text || status !== "succeeded")) return false;
|
|
67
|
+
if (!deliverables.length && personalRequestForTask(run.taskId)) return false;
|
|
68
|
+
const outcome = {
|
|
69
|
+
...latest,
|
|
70
|
+
deliverables,
|
|
71
|
+
evidence: [],
|
|
72
|
+
changeSet: void 0,
|
|
73
|
+
summary: summary.slice(0, 2e3),
|
|
74
|
+
status: status === "failed" || deliverables.some((item) => item.availability !== "available") ? "partial" : "succeeded"
|
|
75
|
+
};
|
|
76
|
+
const now = Date.now();
|
|
77
|
+
const delivery = TaskResultDeliverySchema.parse({
|
|
78
|
+
version: 1,
|
|
79
|
+
deliveryId: randomUUID(),
|
|
80
|
+
taskId: run.taskId,
|
|
81
|
+
taskRunId: runId,
|
|
82
|
+
taskTitle: origin.title.slice(0, 300),
|
|
83
|
+
conversationId: origin.conversation_id,
|
|
84
|
+
originTranscriptId: origin.origin_transcript_id,
|
|
85
|
+
...origin.request_input_id ? { requestInputId: origin.request_input_id } : {},
|
|
86
|
+
assignmentEpoch: state.assignmentEpoch,
|
|
87
|
+
outcome,
|
|
88
|
+
...text ? { text } : {},
|
|
89
|
+
createdAt: now
|
|
90
|
+
});
|
|
91
|
+
db.prepare(`INSERT INTO task_result_deliveries
|
|
92
|
+
(delivery_id, task_run_id, conversation_id, payload_json, status, next_attempt_at, created_at)
|
|
93
|
+
VALUES (?, ?, ?, ?, 'pending', ?, ?) ON CONFLICT(task_run_id, conversation_id) DO NOTHING`).run(delivery.deliveryId, runId, origin.conversation_id, JSON.stringify(delivery), now, now);
|
|
94
|
+
db.prepare(`UPDATE task_main_update_deliveries SET status = 'delivered', decision = 'silent',
|
|
95
|
+
decision_reason = 'Structured task result delivery', updated_at = ?
|
|
96
|
+
WHERE entry_id IN (SELECT entry_id FROM task_collaboration_entries
|
|
97
|
+
WHERE task_run_id = ? AND kind IN ('result', 'progress'))`).run(now, runId);
|
|
98
|
+
afterSqliteCommit(() => {
|
|
99
|
+
for (const listener of queuedListeners) try {
|
|
100
|
+
listener();
|
|
101
|
+
} catch (err) {
|
|
102
|
+
log.warn({
|
|
103
|
+
err,
|
|
104
|
+
runId
|
|
105
|
+
}, "Task result wake failed; polling will recover");
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
hasForRun(runId) {
|
|
111
|
+
return Boolean(getSqliteDatabase().prepare(`SELECT 1 FROM task_result_deliveries
|
|
112
|
+
WHERE task_run_id = ? AND status IN ('pending', 'delivered')`).get(runId));
|
|
113
|
+
}
|
|
114
|
+
hasCapturedOutcome(runId) {
|
|
115
|
+
return Boolean(getSqliteDatabase().prepare("SELECT 1 FROM task_run_outcomes WHERE task_run_id = ? LIMIT 1").get(runId));
|
|
116
|
+
}
|
|
117
|
+
pending(limit = 20) {
|
|
118
|
+
return getSqliteDatabase().prepare(`SELECT * FROM task_result_deliveries
|
|
119
|
+
WHERE status IN ('pending', 'delivered') AND next_attempt_at <= ? AND notified_at IS NULL
|
|
120
|
+
ORDER BY created_at LIMIT ?`).all(Date.now(), limit);
|
|
121
|
+
}
|
|
122
|
+
retry(id, error) {
|
|
123
|
+
runSqliteWriteTransaction((db) => {
|
|
124
|
+
db.prepare(`UPDATE task_result_deliveries SET attempts = attempts + 1,
|
|
125
|
+
status = CASE WHEN status = 'pending' AND attempts >= 7 THEN 'failed' ELSE status END,
|
|
126
|
+
notified_at = CASE WHEN status = 'delivered' AND attempts >= 7 THEN -1 ELSE notified_at END,
|
|
127
|
+
next_attempt_at = ? + MIN(60000, 1000 * (1 << MIN(attempts, 6))), last_error = ?
|
|
128
|
+
WHERE delivery_id = ? AND status IN ('pending', 'delivered')`).run(Date.now(), error.slice(0, 500), id);
|
|
129
|
+
const row = db.prepare("SELECT task_run_id FROM task_result_deliveries WHERE delivery_id = ? AND status = 'failed'").get(id);
|
|
130
|
+
const run = row ? new TaskRunRepository().get(row.task_run_id) : void 0;
|
|
131
|
+
if (run) new TaskCollaborationRepository().append({
|
|
132
|
+
taskId: run.taskId,
|
|
133
|
+
taskRunId: run.id,
|
|
134
|
+
authorKind: "system",
|
|
135
|
+
authorId: "task-result-delivery",
|
|
136
|
+
kind: "failure",
|
|
137
|
+
body: "The task produced results, but delivery to the main chat failed. Inspect the published artifacts and retry delivery; do not regenerate paid outputs just to send them.",
|
|
138
|
+
idempotencyKey: `task-result-delivery-failed:${id}`
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
//#endregion
|
|
144
|
+
export { TaskResultDeliveryRepository, onTaskResultQueued };
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../utils/logger.js";
|
|
3
|
+
import { getSqliteDatabase, init_transaction, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
4
|
+
import { TaskResultDeliverySchema } from "../../packages/gateway-contract/src/task-result-delivery.js";
|
|
5
|
+
import { init_src } from "../../packages/gateway-contract/src/index.js";
|
|
6
|
+
import { TaskRunRepository, init_task_run_repository } from "./task-run-repository.js";
|
|
7
|
+
import { appendTranscriptEntry, init_transcript_repository } from "../storage/sqlite/transcript-repository.js";
|
|
8
|
+
import { TaskConversationRepository } from "./task-conversation-repository.js";
|
|
9
|
+
import { tryParseMediaUri } from "../media/uri.js";
|
|
10
|
+
import { resolveMediaBufferPath } from "../media/store.js";
|
|
11
|
+
import { emitSessionTranscriptUpdate } from "../session/transcript-events.js";
|
|
12
|
+
import { TaskResultDeliveryRepository } from "./task-result-delivery-repository.js";
|
|
13
|
+
import { lstat } from "node:fs/promises";
|
|
14
|
+
//#region src/tasks/task-result-delivery-service.ts
|
|
15
|
+
init_src();
|
|
16
|
+
init_transcript_repository();
|
|
17
|
+
init_transaction();
|
|
18
|
+
init_logger();
|
|
19
|
+
init_task_run_repository();
|
|
20
|
+
const log = createLogger("TaskResultDelivery");
|
|
21
|
+
async function materializedArtifact(item) {
|
|
22
|
+
const { workspaceRelativePath: _path, thumbnailUrl: _thumbnail, ...artifact } = item;
|
|
23
|
+
if (item.availability !== "available") return {
|
|
24
|
+
...artifact,
|
|
25
|
+
uri: void 0,
|
|
26
|
+
shareUrl: void 0,
|
|
27
|
+
capabilities: []
|
|
28
|
+
};
|
|
29
|
+
const media = item.uri ? tryParseMediaUri(item.uri) : null;
|
|
30
|
+
if (media?.bucket === "outbound" && item.location === "artifact_store") {
|
|
31
|
+
const file = await lstat(resolveMediaBufferPath(media.id, media.bucket)).catch(() => null);
|
|
32
|
+
if (file?.isFile() && file.size <= 52428800) return {
|
|
33
|
+
...artifact,
|
|
34
|
+
sizeBytes: file.size,
|
|
35
|
+
shareUrl: void 0,
|
|
36
|
+
capabilities: item.capabilities.filter((capability) => capability === "preview" || capability === "download")
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
...artifact,
|
|
40
|
+
availability: "missing",
|
|
41
|
+
uri: void 0,
|
|
42
|
+
shareUrl: void 0,
|
|
43
|
+
capabilities: []
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (item.kind === "site" && item.location === "external_host") try {
|
|
47
|
+
const url = new URL(item.shareUrl ?? item.uri ?? "");
|
|
48
|
+
if (url.protocol === "https:" && !url.username && !url.password) return {
|
|
49
|
+
...artifact,
|
|
50
|
+
uri: url.href,
|
|
51
|
+
shareUrl: url.href,
|
|
52
|
+
capabilities: ["open"]
|
|
53
|
+
};
|
|
54
|
+
} catch {}
|
|
55
|
+
return {
|
|
56
|
+
...artifact,
|
|
57
|
+
availability: "failed",
|
|
58
|
+
uri: void 0,
|
|
59
|
+
shareUrl: void 0,
|
|
60
|
+
capabilities: []
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
var TaskResultDeliveryService = class {
|
|
64
|
+
#repository = new TaskResultDeliveryRepository();
|
|
65
|
+
async drain(notify, limit = 20) {
|
|
66
|
+
let delivered = 0;
|
|
67
|
+
for (const row of this.#repository.pending(limit)) try {
|
|
68
|
+
const delivery = TaskResultDeliverySchema.parse(JSON.parse(row.payload_json));
|
|
69
|
+
if (row.status === "pending") {
|
|
70
|
+
const deliverables = await Promise.all(delivery.outcome.deliverables.map(materializedArtifact));
|
|
71
|
+
if (!runSqliteWriteTransaction((db) => {
|
|
72
|
+
const current = db.prepare("SELECT status FROM task_result_deliveries WHERE delivery_id = ?").get(row.delivery_id);
|
|
73
|
+
if (current?.status !== "pending") return current?.status === "delivered";
|
|
74
|
+
const run = new TaskRunRepository().get(delivery.taskRunId);
|
|
75
|
+
const state = new TaskConversationRepository().getState(delivery.taskId);
|
|
76
|
+
const session = db.prepare("SELECT active_transcript_id FROM sessions WHERE conversation_id = ?").get(delivery.conversationId);
|
|
77
|
+
const task = db.prepare("SELECT resolution FROM tasks WHERE task_id = ?").get(delivery.taskId);
|
|
78
|
+
if (!session || !run || !["succeeded", "failed"].includes(run.status) || task.resolution && task.resolution !== "done" || new TaskRunRepository().getLatestRoot(delivery.taskId)?.id !== run.id || state?.assignmentEpoch !== delivery.assignmentEpoch || state.activeConversationId !== run.conversationId) {
|
|
79
|
+
db.prepare("UPDATE task_result_deliveries SET status = 'stale' WHERE delivery_id = ?").run(row.delivery_id);
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
const available = deliverables.filter((item) => item.availability === "available").length;
|
|
83
|
+
const outcome = {
|
|
84
|
+
...delivery.outcome,
|
|
85
|
+
deliverables,
|
|
86
|
+
status: deliverables.length > 0 && available === 0 ? "failed" : available < deliverables.length ? "partial" : delivery.outcome.status
|
|
87
|
+
};
|
|
88
|
+
const statusText = db.prepare("SELECT locale FROM tasks WHERE task_id = ?").get(delivery.taskId).locale?.startsWith("zh") === true ? `${delivery.taskTitle}:${available === deliverables.length ? "成果已生成" : available > 0 ? "部分成果已生成" : "成果暂不可用"}。` : `${delivery.taskTitle}: ${available === deliverables.length ? "Results ready" : available > 0 ? "Partial results ready" : "Results unavailable"}.`;
|
|
89
|
+
const content = delivery.text ? `${statusText}\n\n${delivery.text}` : statusText;
|
|
90
|
+
const details = {
|
|
91
|
+
...delivery,
|
|
92
|
+
outcome
|
|
93
|
+
};
|
|
94
|
+
const entry = appendTranscriptEntry(delivery.conversationId, {
|
|
95
|
+
role: "custom",
|
|
96
|
+
customType: "task_result_delivery",
|
|
97
|
+
content,
|
|
98
|
+
display: true,
|
|
99
|
+
details,
|
|
100
|
+
timestamp: Date.now()
|
|
101
|
+
});
|
|
102
|
+
db.prepare(`UPDATE task_result_deliveries SET status = 'delivered', payload_json = ?,
|
|
103
|
+
message_entry_id = ?, delivered_at = ? WHERE delivery_id = ?`).run(JSON.stringify(details), entry.entry_id, Date.now(), row.delivery_id);
|
|
104
|
+
return true;
|
|
105
|
+
})) continue;
|
|
106
|
+
}
|
|
107
|
+
emitSessionTranscriptUpdate({ conversationId: delivery.conversationId });
|
|
108
|
+
notify(delivery.conversationId, delivery.deliveryId);
|
|
109
|
+
getSqliteDatabase().prepare("UPDATE task_result_deliveries SET notified_at = ? WHERE delivery_id = ?").run(Date.now(), row.delivery_id);
|
|
110
|
+
delivered += 1;
|
|
111
|
+
log.info({
|
|
112
|
+
conversationId: delivery.conversationId,
|
|
113
|
+
taskId: delivery.taskId,
|
|
114
|
+
deliveryId: delivery.deliveryId,
|
|
115
|
+
durationMs: Date.now() - delivery.createdAt
|
|
116
|
+
}, "Task result delivered to main Chat");
|
|
117
|
+
} catch (error) {
|
|
118
|
+
this.#repository.retry(row.delivery_id, error instanceof Error ? error.message : String(error));
|
|
119
|
+
if (row.attempts === 0 || row.attempts === 7) log.warn({
|
|
120
|
+
err: error,
|
|
121
|
+
deliveryId: row.delivery_id
|
|
122
|
+
}, "Task result delivery failed");
|
|
123
|
+
}
|
|
124
|
+
return delivered;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
//#endregion
|
|
128
|
+
export { TaskResultDeliveryService };
|
|
@@ -2,6 +2,7 @@ import { TaskRepository, init_task_repository } from "./task-repository.js";
|
|
|
2
2
|
import { TaskRunRepository, init_task_run_repository } from "./task-run-repository.js";
|
|
3
3
|
import { TaskContextRepository } from "./task-context-repository.js";
|
|
4
4
|
import { TaskCollaborationRepository } from "./task-collaboration-repository.js";
|
|
5
|
+
import { TaskResultDeliveryRepository } from "./task-result-delivery-repository.js";
|
|
5
6
|
import { TaskApplicationService } from "./task-application-service.js";
|
|
6
7
|
//#region src/tasks/task-run-coordinator.ts
|
|
7
8
|
init_task_repository();
|
|
@@ -10,6 +11,7 @@ var TaskRunCoordinator = class TaskRunCoordinator {
|
|
|
10
11
|
#evidence = [];
|
|
11
12
|
#application = new TaskApplicationService();
|
|
12
13
|
#runs = new TaskRunRepository();
|
|
14
|
+
#hasDeliverables = false;
|
|
13
15
|
constructor(runId) {
|
|
14
16
|
this.runId = runId;
|
|
15
17
|
}
|
|
@@ -81,6 +83,8 @@ var TaskRunCoordinator = class TaskRunCoordinator {
|
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
85
|
captureOutcome(outcome) {
|
|
86
|
+
new TaskResultDeliveryRepository().capture(this.runId, outcome);
|
|
87
|
+
this.#hasDeliverables ||= outcome.deliverables.some((item) => item.availability === "available");
|
|
84
88
|
for (const item of outcome.evidence) {
|
|
85
89
|
if (item.kind !== "check") continue;
|
|
86
90
|
this.addEvidence({
|
|
@@ -113,12 +117,13 @@ var TaskRunCoordinator = class TaskRunCoordinator {
|
|
|
113
117
|
if (run.status === "waiting" && this.#runs.listActiveWaits(run.taskId).length > 0) return;
|
|
114
118
|
const hasAssistantResult = Boolean(input.assistantText?.trim() && input.assistantText.trim() !== "NO_REPLY");
|
|
115
119
|
const hasBoardResult = new TaskCollaborationRepository().recent(run.taskId, void 0, 20).some((entry) => entry.taskRunId === run.id && entry.kind === "result");
|
|
116
|
-
const emptySuccess = input.status === "succeeded" && !hasAssistantResult && !hasBoardResult && this.#evidence.length === 0;
|
|
120
|
+
const emptySuccess = input.status === "succeeded" && !hasAssistantResult && !hasBoardResult && !this.#hasDeliverables && this.#evidence.length === 0;
|
|
117
121
|
const status = emptySuccess ? "failed" : input.status;
|
|
118
122
|
const summary = emptySuccess ? "Agent run returned no result or evidence" : input.summary;
|
|
119
123
|
this.#application.completeRun({
|
|
120
124
|
runId: run.id,
|
|
121
125
|
expectedRunVersion: run.version,
|
|
126
|
+
resultText: input.assistantText,
|
|
122
127
|
receipt: {
|
|
123
128
|
status,
|
|
124
129
|
summary,
|
|
@@ -16,13 +16,24 @@ var TaskRunDispatcher = class {
|
|
|
16
16
|
#application = new TaskApplicationService();
|
|
17
17
|
#draining = /* @__PURE__ */ new Set();
|
|
18
18
|
#activeRunIds = /* @__PURE__ */ new Set();
|
|
19
|
+
#heartbeats = /* @__PURE__ */ new Set();
|
|
20
|
+
#stopped = false;
|
|
19
21
|
constructor(deps) {
|
|
20
22
|
this.deps = deps;
|
|
21
23
|
}
|
|
22
24
|
dispatch() {
|
|
23
|
-
this.drain()
|
|
25
|
+
this.drain().catch((error) => {
|
|
26
|
+
if (this.#stopped) return;
|
|
27
|
+
log.error({ err: error }, `TaskRun dispatch failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
stop() {
|
|
31
|
+
this.#stopped = true;
|
|
32
|
+
for (const heartbeat of this.#heartbeats) clearInterval(heartbeat);
|
|
33
|
+
this.#heartbeats.clear();
|
|
24
34
|
}
|
|
25
35
|
async drain() {
|
|
36
|
+
if (this.#stopped) return;
|
|
26
37
|
this.reconcileExpiredRuns();
|
|
27
38
|
const count = Math.max(1, Math.min(8, this.deps.maxConcurrency ?? 3));
|
|
28
39
|
await Promise.all(Array.from({ length: count }, (_, slot) => this.drainSlot(`${this.deps.workerId}:${slot}`)));
|
|
@@ -67,7 +78,7 @@ var TaskRunDispatcher = class {
|
|
|
67
78
|
if (this.#draining.has(workerId)) return;
|
|
68
79
|
this.#draining.add(workerId);
|
|
69
80
|
try {
|
|
70
|
-
while (
|
|
81
|
+
while (!this.#stopped) {
|
|
71
82
|
const run = this.#runs.claimNext({
|
|
72
83
|
owner: workerId,
|
|
73
84
|
leaseMs: LEASE_MS,
|
|
@@ -89,22 +100,29 @@ var TaskRunDispatcher = class {
|
|
|
89
100
|
}) : run)) continue;
|
|
90
101
|
const agentId = typeof run.executorRef.agentId === "string" ? run.executorRef.agentId : void 0;
|
|
91
102
|
const conversationId = await this.deps.ensureSession(task.id, run.id, agentId);
|
|
103
|
+
if (this.#stopped) return;
|
|
92
104
|
this.#activeRunIds.add(run.id);
|
|
93
105
|
const heartbeat = setInterval(() => {
|
|
94
106
|
if (!this.#runs.heartbeat({
|
|
95
107
|
runId: run.id,
|
|
96
108
|
owner: workerId,
|
|
97
109
|
leaseMs: LEASE_MS
|
|
98
|
-
}))
|
|
110
|
+
})) {
|
|
111
|
+
clearInterval(heartbeat);
|
|
112
|
+
this.#heartbeats.delete(heartbeat);
|
|
113
|
+
}
|
|
99
114
|
}, HEARTBEAT_MS);
|
|
100
115
|
heartbeat.unref?.();
|
|
116
|
+
this.#heartbeats.add(heartbeat);
|
|
101
117
|
try {
|
|
102
118
|
await this.deps.runAgent(run.id, conversationId, buildTaskRunMessage(task.contract?.objective ?? task.title, run.trigger, task.body));
|
|
103
119
|
} finally {
|
|
104
120
|
clearInterval(heartbeat);
|
|
121
|
+
this.#heartbeats.delete(heartbeat);
|
|
105
122
|
this.#activeRunIds.delete(run.id);
|
|
106
123
|
}
|
|
107
124
|
} catch (error) {
|
|
125
|
+
if (this.#stopped) return;
|
|
108
126
|
const current = this.#runs.get(run.id);
|
|
109
127
|
if (current && [
|
|
110
128
|
"queued",
|
|
@@ -142,6 +160,7 @@ var TaskRunDispatcher = class {
|
|
|
142
160
|
}
|
|
143
161
|
}
|
|
144
162
|
} catch (error) {
|
|
163
|
+
if (this.#stopped) return;
|
|
145
164
|
log.error({ err: error }, `TaskRun dispatch failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
146
165
|
} finally {
|
|
147
166
|
this.#draining.delete(workerId);
|