chainlesschain 0.163.6 → 0.163.7
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/package.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-DDIUofA8.js → AIOps-axqQfwv8.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Bm-5xYRn.js → ActionButton-DV-Ro0By.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-D5UH4ljI.js → Analytics-Bt72WEVu.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-D_ifjOOP.js → AppLayout-BtepG55E.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BY1mXdC7.js → Artifacts-B7KaJ7S_.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-Bujr4Ml3.js → Audit-FNFaUg7A.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-sioKSTcC.js → BackgroundAgents-DFb6J2wQ.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DDOAK8RK.js → Backup-CC7YBhyj.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CtCsVVke.js → BaseInput-RkgTNVtj.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-DpNj0vnd.js → Chat-hHEmGZy-.js} +4 -4
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CZta3Ftr.js → ChatBubbleRenderer-CAP9YhHv.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DoHVNSXq.js → Checkbox-z5wXOQP1.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DlVl7Qmv.js → Codegen-DVaDJnxy.js} +1 -1
- package/src/assets/web-panel/assets/{Col-GIqoPYty.js → Col-CJmaRDR5.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CIAPEVji.js → Community-DF29_2bI.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BN7JiI_h.js → Compact-DtkQkBzn.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CqUWCM9B.js → Compliance-xoHDxp7I.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-A4iPp7A4.js → Cowork-BUm-R7ht.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-B2zeXXWb.js → Cron-Cgl14ZkB.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BR2xmWr8.js → Crosschain-BNcbmoqh.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BzFDjrIv.js → DID-Bwja0Zo9.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DKtDo3yA.js → Dashboard-Bk5XjEdJ.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-RNx43_YG.js → Dropdown-Ci36Oitq.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-SwMt4Rcy.js → EmailListRenderer--U04ZN4q.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-CsYebZ4X.js → FamilyGuardDashboard-B2gNPR2s.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BmRKvBTy.js → Federation-C4KghYn7.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CVxGTA-0.js → FormItemContext-QL7x_Q_0.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-x2iXpyB7.js → GenericCardRenderer-F3Ryltwm.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DfqbkiOP.js → Git-2HassK5k.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-RuHyyj5O.js → Governance-DoBIp7oe.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Bn7uZ7rI.js → Inference--W01QhZ-.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DlP7XefZ.js → KnowledgeGraph-DmvwqGpT.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BYNdOiCd.js → Logs-BBJ4yAel.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-aMtgN-R6.js → MarkdownRenderer-BLCZMzhJ.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-JQYmDqM8.js → Marketplace-D5lNngSI.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-Cyx4yZ-9.js → McpTools-CkEVOMKH.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-VDuGZTN2.js → Memory-B1Ow1xVE.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-_yKo97gi.js → MobileBridge-SgYbUfb6.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CXRXW3q7.js → MobileProjects-BWdOvQAj.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-acTGtfLH.js → Mtc-DcTXSSma.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-ClpjXfkY.js → MtcAudit-Dt3WG4oj.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-_6Tn3o96.js → Multisig-B9B38UZx.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CK7pbZzP.js → NLProgramming-B0S4GGvG.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Czy6V_P8.js → Notes-DZ5U58Ng.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-Cqx-UVv3.js → NotificationSettings-PjL5ZW34.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-C69WDxGy.js → OrderTableRenderer-DrAX2ESt.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DFnA9vLQ.js → Organization-Cv1GYs-c.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-ReZkk2yT.js → Overflow-Bbkp_PL3.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DzjSI0aI.js → P2P-BD8QUgoZ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DKTf5xIP.js → PdhVaultBrowser-BO-2PeaB.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-DhQ5klhR.js → Permissions-D_OPVa02.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CUL1iHrW.js → PersonalDataHub-mh-pEmaB.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-DU88iu4N.js → Pipeline-6JC2EDdb.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Bw-sYfyK.js → Privacy-CUshzUAG.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Bq3Q5y0z.js → ProjectInit-Cs2Aalri.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-C8spzpho.js → ProjectSettings-1ak49tcj.js} +2 -2
- package/src/assets/web-panel/assets/Projects-BV4oApsm.js +1 -0
- package/src/assets/web-panel/assets/{Providers-Bf4eTP9W.js → Providers-CXXxvafH.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-Dme9BDU1.js → QrScannerModal-PTcDsF58.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CIXfv1rE.js → QuickAsk-CDwucrJw.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CIxvdeZ-.js → Recommend-CJlLVRXR.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-C6k7MExI.js → RemoteSession-DlN-ETsO.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-CISDz2bl.js → Reputation-DI23LR6m.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CdnDxXyf.js → Row-Cl7UQMrM.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-C-QpRHsl.js → RssFeed-CexHNfh8.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DBjaGzSn.js → Search-BneBWvRN.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CQKukOeE.js → Security-DX7Phgrp.js} +4 -4
- package/src/assets/web-panel/assets/{Services-DZz86jWb.js → Services-BWXO8Mte.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-jb8RMK0d.js → Skeleton-DCyOjKPJ.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CdY76fZG.js → Skills-CXqERsTB.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-C_CSiZX9.js → Sla-bhbrbz8E.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-3IPU0HBZ.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-qvimGO0O.js → SyncSettings-DBNTQLbM.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Dng5LPJC.js → Tasks-quP0bkN-.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-Bwqq5Wll.js → Templates-BouWmgho.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DNWuwP7Z.js → Tenant-qv0D9s7z.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-B-6Othpp.js → Terminal-BxvbE8BB.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DKpKZfzx.js → TimelineRenderer-D-IeLnJ2.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DzfGMd2J.js → Tokens-CFMKKyVG.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BXwUi74J.js → Trigger-L8as3UuJ.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BNzUq4ui.js → Trust-MxmA4VZG.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BYugxww4.js → UkeySign-C0VvJYRi.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DdauhtSJ.js → VideoEditing-Bf5QZj8N.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CSC9bCe_.js → Wallet-BIJ9riRz.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-Q8AN3bTO.js → WebAuthn-B8p9Mhkw.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-d-LBGCuA.js → WorkflowEditor-BVsuaPen.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BLVDCgsZ.js → chat-BfkjoKpV.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BZlPSEHl.js → colors-DeAlsWK8.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-IWseP6R6.js → compact-item-Cs97bz5j.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DnVRV3Ao.js → createContext-BqbG60LH.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DPty0mGN.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DLQZA_Wn.js → hasIn-i_RY0b1X.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_N4-Gq9.js → index-0-agYlWL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DB0MJgF_.js → index-79V_zv1s.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOZJBTWZ.js → index-B-3tEpTc.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUq0c7gq.js → index-B-JVTrpr.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dy0R5ZED.js → index-B1CbOH1i.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bxp7uDD8.js → index-B5UkyA3c.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpVrK6fr.js → index-BESLFt4q.js} +1 -1
- package/src/assets/web-panel/assets/{index-CT9vVN-X.js → index-BOVkf1K3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DOoQpuQY.js → index-BYUVuwKt.js} +1 -1
- package/src/assets/web-panel/assets/{index-CINJQEj6.js → index-BcUXAB2s.js} +1 -1
- package/src/assets/web-panel/assets/{index-CarMTIyQ.js → index-BkBi5TmC.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5dgnilC.js → index-Bm7lLR4c.js} +1 -1
- package/src/assets/web-panel/assets/index-Bt7g0Vq_.js +1 -0
- package/src/assets/web-panel/assets/{index-CbQNL0ue.js → index-BuLQobzW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpBaJ3TD.js → index-CE2VtTlp.js} +1 -1
- package/src/assets/web-panel/assets/{index-jWb70ZgZ.js → index-CED2PL_y.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEu2lMBy.js → index-CG3PRyAL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DocEhinm.js → index-CIG8fQ2_.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_LQodeJ.js → index-COdGA-8n.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZpYeqrh.js → index-CeWoNHau.js} +1 -1
- package/src/assets/web-panel/assets/{index-gt8bNefW.js → index-Cf3WCLmy.js} +1 -1
- package/src/assets/web-panel/assets/{index-N_GoWZX4.js → index-CgsqdnRV.js} +1 -1
- package/src/assets/web-panel/assets/index-ChVT0p9u.js +1 -0
- package/src/assets/web-panel/assets/{index-CZDekj7T.js → index-D2B4VPyP.js} +1 -1
- package/src/assets/web-panel/assets/{index-YSw_gxlZ.js → index-D9evtvg2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTbxp4UH.js → index-DUUrv141.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bbj2NS_I.js → index-DiSkx4UB.js} +3 -3
- package/src/assets/web-panel/assets/{index-BZs5bBnk.js → index-Dk2qouAz.js} +1 -1
- package/src/assets/web-panel/assets/{index-DalA0TKC.js → index-Dk7-v4hP.js} +1 -1
- package/src/assets/web-panel/assets/{index-1jeAudHd.js → index-DmbfhJUP.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1ifZtXo.js → index-DqBgBpgp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BhA3QEni.js → index-PT_5sBMA.js} +1 -1
- package/src/assets/web-panel/assets/{index-BSjilZ9L.js → index-U4f5izHz.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2FqfMvU.js → index-YXgLng0K.js} +1 -1
- package/src/assets/web-panel/assets/{index-COev0W2g.js → index-ZxO_-E8a.js} +1 -1
- package/src/assets/web-panel/assets/{index-M7wxfAbm.js → index-dIHr4B_u.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjWnONdy.js → index-gyFpvL7l.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dkwsi1Kn.js → index-s1opAL-M.js} +1 -1
- package/src/assets/web-panel/assets/{index-hwVDeoC0.js → index-yObj1O4n.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Co67Kqmb.js → initDefaultProps-C9h9yKL3.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BMOxQSF_.js → motion-BvmLsPdu.js} +1 -1
- package/src/assets/web-panel/assets/{move-C5fWDw-N.js → move-CoL4ekU1.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BJevpL0e.js → mtc-parser-C4pMy6xV.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BCzNU8s6.js → omit-DPuJfNxx.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CybWvDPk.js → pickAttrs-D0KEeaK2.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BMWS9HnW.js → placementArrow-BpkyINxt.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BoL2UnGY.js → responsiveObserve-DQI_wOq8.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DWNfXraU.js → slide-DYfdDiRg.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BquTM3tX.js → statusUtils-B5dtvb0D.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BEkCleim.js → styleChecker-CF310mSj.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Oecnq7EA.js → useFlexGapSupport-D1Qp4BLp.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CkDffJ4F.js → useFs-C7_iyvJK.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-qbvKXesB.js → usePersonalDataHub-DZUt_fIm.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-C6v8n6mA.js → vnode-D3dsi0lZ.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-4CTeFILV.js → zoom-WdbOlvdQ.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +2 -2
- package/src/commands/agent.js +90 -1
- package/src/commands/chat.js +11 -2
- package/src/commands/compact.js +106 -23
- package/src/commands/loop.js +28 -10
- package/src/commands/routine.js +1 -1
- package/src/commands/scheduler-daemon.js +359 -2
- package/src/commands/session-observability.js +305 -0
- package/src/commands/session.js +38 -0
- package/src/data/changelog.json +14 -1
- package/src/gateways/ws/ws-agent-handler.js +439 -5
- package/src/harness/jsonl-session-store.js +463 -125
- package/src/harness/prompt-compressor.js +86 -13
- package/src/harness/provider-backed-compaction.js +100 -27
- package/src/lib/advisor-runtime.js +3 -1
- package/src/lib/agent-schedule-store.js +414 -4
- package/src/lib/agent-team/team-adjudication.js +40 -1
- package/src/lib/automation-engine.js +494 -0
- package/src/lib/background-agent-supervisor.js +793 -215
- package/src/lib/background-command-argv.js +24 -0
- package/src/lib/background-interaction-journal.js +361 -52
- package/src/lib/background-interaction-resolver.js +32 -0
- package/src/lib/background-launch-profile.js +2 -0
- package/src/lib/causal-observability.js +2661 -0
- package/src/lib/chat-session-admission.js +76 -0
- package/src/lib/cost-budget.js +5 -7
- package/src/lib/cowork/ab-comparator-cli.js +11 -0
- package/src/lib/cowork/debate-review-cli.js +12 -0
- package/src/lib/cowork-adapter.js +159 -38
- package/src/lib/cowork-cron.js +357 -1
- package/src/lib/cowork-task-runner.js +112 -17
- package/src/lib/delivery-coordinator.js +142 -0
- package/src/lib/direct-model-usage.js +121 -0
- package/src/lib/file-lines.js +183 -47
- package/src/lib/llm-pricing.js +12 -17
- package/src/lib/loop.js +26 -2
- package/src/lib/routine-store.js +380 -21
- package/src/lib/runtime-usage-ledger.js +182 -0
- package/src/lib/scheduler-kernel/agenda-adapter.js +308 -3
- package/src/lib/scheduler-kernel/automation-adapter.js +410 -8
- package/src/lib/scheduler-kernel/automation-event-adapter.js +36 -0
- package/src/lib/scheduler-kernel/cowork-cron-adapter.js +285 -3
- package/src/lib/scheduler-kernel/loop-adapter.js +541 -6
- package/src/lib/scheduler-kernel/migration-admin.js +346 -0
- package/src/lib/scheduler-kernel/migration-rollback-admin.js +932 -0
- package/src/lib/scheduler-kernel/routine-adapter.js +394 -20
- package/src/lib/scheduler-kernel/runtime.js +63 -1
- package/src/lib/scheduler-kernel/source-locator-path.js +142 -0
- package/src/lib/scheduler-kernel/store.js +2586 -85
- package/src/lib/session-host-lease.js +171 -2
- package/src/lib/session-host-snapshot.js +14 -3
- package/src/lib/session-persistence-failure.js +1 -0
- package/src/lib/session-tail.js +179 -34
- package/src/lib/session-transcript-structure.js +96 -0
- package/src/lib/sub-agent-context.js +328 -22
- package/src/lib/ws-agent-handler.js +4 -1
- package/src/repl/agent-repl.js +732 -91
- package/src/repl/chat-repl.js +5 -1
- package/src/runtime/agent-core.js +1272 -207
- package/src/runtime/fallback-model.js +5 -0
- package/src/runtime/headless-runner.js +324 -82
- package/src/runtime/headless-stream.js +232 -26
- package/src/runtime/policies/agent-policy.js +4 -0
- package/src/workers/background-agent-worker.js +403 -96
- package/src/assets/web-panel/assets/Projects-Dd-xuPIc.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-C7tT9iad.js +0 -1
- package/src/assets/web-panel/assets/devWarning-Jzu62CLC.js +0 -1
- package/src/assets/web-panel/assets/index-Zb2MeDSy.js +0 -1
- package/src/assets/web-panel/assets/index-fikqml4k.js +0 -1
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
const MAX_LABEL_LENGTH = 160;
|
|
2
|
+
const MAX_CALL_ID_LENGTH = 128;
|
|
3
|
+
const MAX_ATTRIBUTION_ID_LENGTH = 256;
|
|
4
|
+
let fallbackToolSequence = 0;
|
|
5
|
+
const USAGE_FIELDS = Object.freeze([
|
|
6
|
+
["input_tokens", "prompt_tokens"],
|
|
7
|
+
["output_tokens", "completion_tokens"],
|
|
8
|
+
["cache_read_input_tokens", "cache_read_tokens"],
|
|
9
|
+
["cache_creation_input_tokens", "cache_creation_tokens"],
|
|
10
|
+
]);
|
|
11
|
+
const SOURCES = new Set(["model", "semantic-compaction", "subagent"]);
|
|
12
|
+
const UNKNOWN_CODES = new Set([
|
|
13
|
+
"provider_call_failed",
|
|
14
|
+
"provider_usage_missing",
|
|
15
|
+
"provider_transport_outcome_unknown",
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
function cleanLabel(value, max = MAX_LABEL_LENGTH) {
|
|
19
|
+
if (typeof value !== "string") return null;
|
|
20
|
+
const clean = value.replace(/\p{Cc}/gu, "").trim();
|
|
21
|
+
return clean ? clean.slice(0, max) : null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function tokenCount(usage, canonical, alias, { required = false } = {}) {
|
|
25
|
+
const hasCanonical = Object.hasOwn(usage, canonical);
|
|
26
|
+
const hasAlias = Object.hasOwn(usage, alias);
|
|
27
|
+
if (!hasCanonical && !hasAlias) {
|
|
28
|
+
if (required) {
|
|
29
|
+
throw new TypeError(
|
|
30
|
+
`runtime token usage requires ${canonical} or ${alias}`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
if (hasCanonical && hasAlias && usage[canonical] !== usage[alias]) {
|
|
36
|
+
throw new TypeError("runtime token usage aliases conflict");
|
|
37
|
+
}
|
|
38
|
+
const selected = hasCanonical ? usage[canonical] : usage[alias];
|
|
39
|
+
if (
|
|
40
|
+
typeof selected !== "number" ||
|
|
41
|
+
!Number.isSafeInteger(selected) ||
|
|
42
|
+
selected < 0
|
|
43
|
+
) {
|
|
44
|
+
throw new TypeError(
|
|
45
|
+
"runtime token usage must contain non-negative safe integers",
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
return selected;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function source(value, fallback = "model") {
|
|
52
|
+
return SOURCES.has(value) ? value : fallback;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function callId(value, { required = false } = {}) {
|
|
56
|
+
if (
|
|
57
|
+
typeof value !== "string" ||
|
|
58
|
+
!value.trim() ||
|
|
59
|
+
value.length > MAX_CALL_ID_LENGTH ||
|
|
60
|
+
/\p{Cc}/u.test(value)
|
|
61
|
+
) {
|
|
62
|
+
if (!required && value === undefined) return null;
|
|
63
|
+
throw new TypeError("runtime usage boundary requires a bounded call id");
|
|
64
|
+
}
|
|
65
|
+
return value.trim();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function projectAttribution(value) {
|
|
69
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
70
|
+
const projected = {};
|
|
71
|
+
for (const field of [
|
|
72
|
+
"origin",
|
|
73
|
+
"skill",
|
|
74
|
+
"subagentId",
|
|
75
|
+
"role",
|
|
76
|
+
"parentSessionId",
|
|
77
|
+
]) {
|
|
78
|
+
const clean = cleanLabel(value[field], MAX_ATTRIBUTION_ID_LENGTH);
|
|
79
|
+
if (clean) projected[field] = clean;
|
|
80
|
+
}
|
|
81
|
+
if (
|
|
82
|
+
typeof value.depth === "number" &&
|
|
83
|
+
Number.isSafeInteger(value.depth) &&
|
|
84
|
+
value.depth >= 0 &&
|
|
85
|
+
value.depth <= 64
|
|
86
|
+
) {
|
|
87
|
+
projected.depth = value.depth;
|
|
88
|
+
}
|
|
89
|
+
return Object.keys(projected).length > 0 ? projected : null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Project a runtime token event onto the secret-free persisted ledger schema. */
|
|
93
|
+
export function projectRuntimeTokenUsage(event = {}) {
|
|
94
|
+
if (
|
|
95
|
+
!event.usage ||
|
|
96
|
+
typeof event.usage !== "object" ||
|
|
97
|
+
Array.isArray(event.usage)
|
|
98
|
+
) {
|
|
99
|
+
throw new TypeError("runtime token usage requires an object");
|
|
100
|
+
}
|
|
101
|
+
const usage = {};
|
|
102
|
+
for (const [index, [canonical, alias]] of USAGE_FIELDS.entries()) {
|
|
103
|
+
usage[canonical] = tokenCount(event.usage, canonical, alias, {
|
|
104
|
+
// A known settlement must prove both billable input and output counts.
|
|
105
|
+
// Cache counters are optional because many providers do not expose them.
|
|
106
|
+
required: index < 2,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
if (Object.hasOwn(event.usage, "total_tokens")) {
|
|
110
|
+
const total = event.usage.total_tokens;
|
|
111
|
+
if (
|
|
112
|
+
typeof total !== "number" ||
|
|
113
|
+
!Number.isSafeInteger(total) ||
|
|
114
|
+
total < 0 ||
|
|
115
|
+
total !== usage.input_tokens + usage.output_tokens
|
|
116
|
+
) {
|
|
117
|
+
throw new TypeError(
|
|
118
|
+
"runtime token usage total conflicts with components",
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const projectedCallId = callId(event.callId);
|
|
123
|
+
const attribution = projectAttribution(event.attribution);
|
|
124
|
+
return {
|
|
125
|
+
provider: cleanLabel(event.provider),
|
|
126
|
+
model: cleanLabel(event.model),
|
|
127
|
+
usage,
|
|
128
|
+
...(projectedCallId ? { callId: projectedCallId } : {}),
|
|
129
|
+
...(event.source ? { source: source(event.source) } : {}),
|
|
130
|
+
...(attribution ? { attribution } : {}),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Project started/unknown boundaries without retaining provider error text. */
|
|
135
|
+
export function projectRuntimeUsageBoundary(event = {}, outcome) {
|
|
136
|
+
if (outcome !== "started" && outcome !== "unknown") {
|
|
137
|
+
throw new TypeError(
|
|
138
|
+
"runtime usage boundary outcome must be started or unknown",
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
const projected = {
|
|
142
|
+
callId: callId(event.callId, { required: true }),
|
|
143
|
+
provider: cleanLabel(event.provider),
|
|
144
|
+
model: cleanLabel(event.model),
|
|
145
|
+
source: source(event.source),
|
|
146
|
+
};
|
|
147
|
+
const attribution = projectAttribution(event.attribution);
|
|
148
|
+
if (attribution) projected.attribution = attribution;
|
|
149
|
+
if (outcome === "unknown") {
|
|
150
|
+
projected.code = UNKNOWN_CODES.has(event.code)
|
|
151
|
+
? event.code
|
|
152
|
+
: "provider_transport_outcome_unknown";
|
|
153
|
+
}
|
|
154
|
+
return projected;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function runtimeUsageEventType(outcome) {
|
|
158
|
+
return outcome === "started" ? "model_usage_started" : "model_usage_unknown";
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function runtimeToolCallId(value) {
|
|
162
|
+
const projected = callId(value);
|
|
163
|
+
if (projected) return projected;
|
|
164
|
+
fallbackToolSequence = (fallbackToolSequence + 1) % Number.MAX_SAFE_INTEGER;
|
|
165
|
+
return `tool-${Date.now().toString(36)}-${fallbackToolSequence.toString(36)}`;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function markRuntimeLedgerPersistenceError(error) {
|
|
169
|
+
if (error && (typeof error === "object" || typeof error === "function")) {
|
|
170
|
+
try {
|
|
171
|
+
error.runtimeLedgerPersistence = true;
|
|
172
|
+
if (error.runtimeLedgerPersistence === true) return error;
|
|
173
|
+
} catch {
|
|
174
|
+
// Frozen/non-extensible errors are wrapped below.
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const wrapped = new Error("runtime usage ledger persistence failed", {
|
|
178
|
+
cause: error,
|
|
179
|
+
});
|
|
180
|
+
wrapped.runtimeLedgerPersistence = true;
|
|
181
|
+
return wrapped;
|
|
182
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { effectiveFireAt } from "../schedule-planner.js";
|
|
3
3
|
import {
|
|
4
|
+
agendaMigrationSourceDigest,
|
|
5
|
+
agendaMigrationSourceSnapshot,
|
|
4
6
|
nextCronTime,
|
|
5
7
|
normalizeTimeZone,
|
|
6
8
|
parseCron,
|
|
@@ -13,10 +15,12 @@ import {
|
|
|
13
15
|
normalizeJson,
|
|
14
16
|
} from "./contract.js";
|
|
15
17
|
import { SchedulerRuntime } from "./runtime.js";
|
|
18
|
+
import { schedulerMigrationSourceDigest } from "./store.js";
|
|
16
19
|
import {
|
|
17
20
|
bindSchedulerAuthorityPolicy,
|
|
18
21
|
createSchedulerAuthorityResolver,
|
|
19
22
|
} from "./authority-resolver.js";
|
|
23
|
+
import { canonicalSchedulerSourcePath } from "./source-locator-path.js";
|
|
20
24
|
|
|
21
25
|
export const AGENDA_SCHEDULER_KIND = "agenda";
|
|
22
26
|
export const AGENDA_SCHEDULER_CAPABILITY = "agent.execute";
|
|
@@ -188,6 +192,7 @@ function validateEntrySnapshot(entry) {
|
|
|
188
192
|
const plain = { ...entry };
|
|
189
193
|
delete plain.executionLease;
|
|
190
194
|
delete plain.schedulerExecution;
|
|
195
|
+
delete plain.schedulerMigration;
|
|
191
196
|
const snapshot = normalizeJson(plain, "agendaEntrySnapshot");
|
|
192
197
|
snapshot.id = normalizeIdentifier(snapshot.id, "agenda.entry.id");
|
|
193
198
|
if (!AGENDA_SCHEDULER_ENTRY_KINDS.includes(snapshot.kind)) {
|
|
@@ -361,6 +366,223 @@ export function syncAgendaSchedulerJob(schedulerStore, entry) {
|
|
|
361
366
|
}
|
|
362
367
|
}
|
|
363
368
|
|
|
369
|
+
export function migrateAgendaSchedulerEntry({
|
|
370
|
+
agendaStore,
|
|
371
|
+
schedulerStore,
|
|
372
|
+
entry,
|
|
373
|
+
}) {
|
|
374
|
+
const snapshot = agendaEntrySnapshot(entry);
|
|
375
|
+
const directory = canonicalSchedulerSourcePath(agendaStore.dir);
|
|
376
|
+
const sourceScope = { store: "agent-schedule", directory };
|
|
377
|
+
const sourceLocator = {
|
|
378
|
+
schemaVersion: 1,
|
|
379
|
+
type: "agenda-store",
|
|
380
|
+
directory,
|
|
381
|
+
};
|
|
382
|
+
let prepared = schedulerStore.getActiveDomainMigrationBySource({
|
|
383
|
+
domain: "agenda",
|
|
384
|
+
sourceScope,
|
|
385
|
+
sourceId: snapshot.id,
|
|
386
|
+
});
|
|
387
|
+
if (!prepared && agendaStore.dir !== directory) {
|
|
388
|
+
const ambiguousLegacy = schedulerStore.getActiveDomainMigrationBySource({
|
|
389
|
+
domain: "agenda",
|
|
390
|
+
sourceScope: {
|
|
391
|
+
store: "agent-schedule",
|
|
392
|
+
directory: agendaStore.dir,
|
|
393
|
+
},
|
|
394
|
+
sourceId: snapshot.id,
|
|
395
|
+
});
|
|
396
|
+
if (ambiguousLegacy) {
|
|
397
|
+
throw agendaError(
|
|
398
|
+
"AGENDA_SCHEDULER_MIGRATION_SOURCE_UNBOUND",
|
|
399
|
+
`Legacy Agenda migration uses a non-canonical path scope and cannot be bound safely: ${snapshot.id}`,
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
const desired = buildAgendaSchedulerJob(snapshot);
|
|
404
|
+
desired.authority = bindSchedulerAuthorityPolicy(
|
|
405
|
+
schedulerStore,
|
|
406
|
+
desired.authority,
|
|
407
|
+
);
|
|
408
|
+
const sourceDigest = agendaMigrationSourceDigest(entry);
|
|
409
|
+
const sourceSnapshot = agendaMigrationSourceSnapshot(entry);
|
|
410
|
+
if (prepared) {
|
|
411
|
+
const migrationEntries = prepared.entries.filter(
|
|
412
|
+
(candidate) =>
|
|
413
|
+
candidate.domain === "agenda" && candidate.sourceId === snapshot.id,
|
|
414
|
+
);
|
|
415
|
+
if (prepared.entries.length !== 1 || migrationEntries.length !== 1) {
|
|
416
|
+
throw agendaError(
|
|
417
|
+
"AGENDA_SCHEDULER_MIGRATION_DOMAIN_MISMATCH",
|
|
418
|
+
"Agenda entry belongs to an invalid mixed-domain migration",
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
const [migrationEntry] = migrationEntries;
|
|
422
|
+
schedulerStore.bindDomainMigrationSourceLocator({
|
|
423
|
+
migrationId: prepared.id,
|
|
424
|
+
entryId: migrationEntry.entryId,
|
|
425
|
+
sourceLocator,
|
|
426
|
+
expectedSourceDigest: migrationEntry.sourceDigest,
|
|
427
|
+
expectedTargetJobId: migrationEntry.targetJobId,
|
|
428
|
+
});
|
|
429
|
+
prepared = schedulerStore.getDomainMigration(prepared.id);
|
|
430
|
+
} else {
|
|
431
|
+
prepared = schedulerStore.prepareDomainMigration({
|
|
432
|
+
entries: [
|
|
433
|
+
{
|
|
434
|
+
domain: "agenda",
|
|
435
|
+
sourceId: snapshot.id,
|
|
436
|
+
sourceScope,
|
|
437
|
+
sourceLocator,
|
|
438
|
+
source: sourceSnapshot,
|
|
439
|
+
targetJob: desired,
|
|
440
|
+
rollbackStrategy: "disable",
|
|
441
|
+
},
|
|
442
|
+
],
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
if (
|
|
446
|
+
prepared.entries.length !== 1 ||
|
|
447
|
+
prepared.entries[0].domain !== "agenda"
|
|
448
|
+
) {
|
|
449
|
+
throw agendaError(
|
|
450
|
+
"AGENDA_SCHEDULER_MIGRATION_DOMAIN_MISMATCH",
|
|
451
|
+
"Agenda entry belongs to an invalid mixed-domain migration",
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
const expectedJournalDigest = schedulerMigrationSourceDigest(sourceSnapshot);
|
|
455
|
+
if (
|
|
456
|
+
prepared.entries[0].sourceDigest !== expectedJournalDigest ||
|
|
457
|
+
prepared.entries[0].targetJobId !== desired.id
|
|
458
|
+
) {
|
|
459
|
+
throw agendaError(
|
|
460
|
+
"AGENDA_SCHEDULER_MIGRATION_SOURCE_CHANGED",
|
|
461
|
+
`Agenda entry changed after its scheduler migration started: ${snapshot.id}`,
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
let migration = prepared;
|
|
465
|
+
if (migration.state === "rolled_back" || migration.state === "rolling_back") {
|
|
466
|
+
throw agendaError(
|
|
467
|
+
"AGENDA_SCHEDULER_MIGRATION_STATE_CONFLICT",
|
|
468
|
+
`Agenda migration cannot resume from state ${migration.state}`,
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
if (migration.state === "retired") {
|
|
472
|
+
const migrationEntry = migration.entries[0];
|
|
473
|
+
agendaStore.retireForSchedulerMigration(snapshot.id, {
|
|
474
|
+
migrationId: migration.id,
|
|
475
|
+
sourceDigest,
|
|
476
|
+
targetJobId: desired.id,
|
|
477
|
+
retirementToken: migrationEntry.retirementToken,
|
|
478
|
+
});
|
|
479
|
+
return migration;
|
|
480
|
+
}
|
|
481
|
+
if (migration.state === "prepared") {
|
|
482
|
+
agendaStore.prepareSchedulerMigration(snapshot.id, {
|
|
483
|
+
migrationId: migration.id,
|
|
484
|
+
sourceDigest,
|
|
485
|
+
targetJobId: desired.id,
|
|
486
|
+
});
|
|
487
|
+
migration = schedulerStore.applyDomainMigration(migration.id);
|
|
488
|
+
}
|
|
489
|
+
if (migration.state === "applied") {
|
|
490
|
+
migration = schedulerStore.verifyDomainMigration(migration.id, {
|
|
491
|
+
sources: [
|
|
492
|
+
{
|
|
493
|
+
entryId: migration.entries[0].entryId,
|
|
494
|
+
source: agendaMigrationSourceSnapshot(entry),
|
|
495
|
+
},
|
|
496
|
+
],
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
const retiring =
|
|
500
|
+
migration.state === "retiring"
|
|
501
|
+
? migration
|
|
502
|
+
: schedulerStore.beginDomainMigrationRetirement(migration.id);
|
|
503
|
+
const retiringEntry = retiring.entries[0];
|
|
504
|
+
const retired = agendaStore.retireForSchedulerMigration(snapshot.id, {
|
|
505
|
+
migrationId: prepared.id,
|
|
506
|
+
sourceDigest,
|
|
507
|
+
targetJobId: desired.id,
|
|
508
|
+
retirementToken: retiringEntry.retirementToken,
|
|
509
|
+
});
|
|
510
|
+
schedulerStore.confirmDomainMigrationEntryRetired({
|
|
511
|
+
migrationId: prepared.id,
|
|
512
|
+
entryId: retiringEntry.entryId,
|
|
513
|
+
retirementToken: retiringEntry.retirementToken,
|
|
514
|
+
source: retired,
|
|
515
|
+
});
|
|
516
|
+
return schedulerStore.getDomainMigration(prepared.id);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
export function rollbackAgendaSchedulerMigration({
|
|
520
|
+
agendaStore,
|
|
521
|
+
schedulerStore,
|
|
522
|
+
migrationId,
|
|
523
|
+
}) {
|
|
524
|
+
const directory = canonicalSchedulerSourcePath(agendaStore.dir);
|
|
525
|
+
const assertRollbackBinding = (migration) => {
|
|
526
|
+
if (
|
|
527
|
+
migration?.id !== migrationId ||
|
|
528
|
+
!Array.isArray(migration.entries) ||
|
|
529
|
+
migration.entries.length === 0 ||
|
|
530
|
+
migration.entries.some((entry) => entry.domain !== "agenda")
|
|
531
|
+
) {
|
|
532
|
+
throw agendaError(
|
|
533
|
+
"AGENDA_SCHEDULER_MIGRATION_DOMAIN_MISMATCH",
|
|
534
|
+
"Agenda rollback cannot operate on a mixed-domain migration",
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
for (const entry of migration.entries) {
|
|
538
|
+
const locator = entry.sourceLocator;
|
|
539
|
+
if (
|
|
540
|
+
locator?.schemaVersion !== 1 ||
|
|
541
|
+
locator.type !== "agenda-store" ||
|
|
542
|
+
locator.directory !== directory
|
|
543
|
+
) {
|
|
544
|
+
throw agendaError(
|
|
545
|
+
"AGENDA_SCHEDULER_MIGRATION_SOURCE_UNBOUND",
|
|
546
|
+
`Agenda rollback source locator does not match its store: ${entry.sourceId}`,
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
return migration;
|
|
551
|
+
};
|
|
552
|
+
const current = assertRollbackBinding(
|
|
553
|
+
schedulerStore.getDomainMigration(migrationId),
|
|
554
|
+
);
|
|
555
|
+
if (current.state === "rolled_back") {
|
|
556
|
+
return { ...current, deduplicated: true };
|
|
557
|
+
}
|
|
558
|
+
const migration = assertRollbackBinding(
|
|
559
|
+
schedulerStore.beginDomainMigrationRollback(migrationId),
|
|
560
|
+
);
|
|
561
|
+
if (migration.state === "rolled_back") return migration;
|
|
562
|
+
const entries = migration.entries;
|
|
563
|
+
for (const entry of entries) {
|
|
564
|
+
if (entry.state === "rolled_back") continue;
|
|
565
|
+
schedulerStore.restoreDomainMigrationEntrySource({
|
|
566
|
+
migrationId,
|
|
567
|
+
entryId: entry.entryId,
|
|
568
|
+
retirementToken: entry.retirementToken,
|
|
569
|
+
restoreSource: () => {
|
|
570
|
+
const current = agendaStore.get(entry.sourceId);
|
|
571
|
+
const restored = current.schedulerMigration
|
|
572
|
+
? agendaStore.restoreFromSchedulerMigration(entry.sourceId, {
|
|
573
|
+
migrationId,
|
|
574
|
+
sourceDigest: agendaMigrationSourceDigest(current),
|
|
575
|
+
targetJobId: entry.targetJobId,
|
|
576
|
+
retirementToken: entry.retirementToken,
|
|
577
|
+
})
|
|
578
|
+
: current;
|
|
579
|
+
return agendaMigrationSourceSnapshot(restored);
|
|
580
|
+
},
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
return schedulerStore.getDomainMigration(migrationId);
|
|
584
|
+
}
|
|
585
|
+
|
|
364
586
|
export function enqueueAgendaEntry(schedulerStore, entry) {
|
|
365
587
|
const snapshot = agendaEntrySnapshot(entry);
|
|
366
588
|
const job = syncAgendaSchedulerJob(schedulerStore, snapshot);
|
|
@@ -455,6 +677,40 @@ export function createAgendaSchedulerAdapter({
|
|
|
455
677
|
}
|
|
456
678
|
return {
|
|
457
679
|
kind: AGENDA_SCHEDULER_KIND,
|
|
680
|
+
async adjudicate({ occurrence, adjudication }) {
|
|
681
|
+
const payload = occurrence.payload;
|
|
682
|
+
const expected = agendaEntrySnapshot(payload?.entry);
|
|
683
|
+
const expectedDigest = agendaEntrySnapshotDigest(expected);
|
|
684
|
+
if (
|
|
685
|
+
payload.snapshotDigest !== expectedDigest ||
|
|
686
|
+
typeof agendaStore.adjudicateSchedulerExecution !== "function"
|
|
687
|
+
) {
|
|
688
|
+
throw agendaError(
|
|
689
|
+
"AGENDA_SCHEDULER_ADJUDICATION_UNSUPPORTED",
|
|
690
|
+
`Agenda adjudication cannot be applied: ${occurrence.id}`,
|
|
691
|
+
);
|
|
692
|
+
}
|
|
693
|
+
agendaStore.adjudicateSchedulerExecution(expected.id, {
|
|
694
|
+
occurrenceId: occurrence.id,
|
|
695
|
+
snapshotDigest: expectedDigest,
|
|
696
|
+
attempt: adjudication.expectedAttempt,
|
|
697
|
+
decision: adjudication.decision,
|
|
698
|
+
requestId: adjudication.requestId,
|
|
699
|
+
atMs: now(),
|
|
700
|
+
});
|
|
701
|
+
if (adjudication.decision === "confirmed_applied") {
|
|
702
|
+
return {
|
|
703
|
+
settled: true,
|
|
704
|
+
result: {
|
|
705
|
+
id: expected.id,
|
|
706
|
+
kind: expected.kind,
|
|
707
|
+
action: "adjudicated-applied",
|
|
708
|
+
adjudicationRequestId: adjudication.requestId,
|
|
709
|
+
},
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
return { continue: true };
|
|
713
|
+
},
|
|
458
714
|
async execute({ occurrence }) {
|
|
459
715
|
const payload = occurrence.payload;
|
|
460
716
|
const expected = agendaEntrySnapshot(payload?.entry);
|
|
@@ -709,6 +965,7 @@ export class AgendaSchedulerBridge {
|
|
|
709
965
|
leaseMs,
|
|
710
966
|
renewIntervalMs,
|
|
711
967
|
authorityResolver,
|
|
968
|
+
migrateLegacy = true,
|
|
712
969
|
} = {}) {
|
|
713
970
|
if (typeof now !== "function") {
|
|
714
971
|
throw agendaError(
|
|
@@ -719,6 +976,7 @@ export class AgendaSchedulerBridge {
|
|
|
719
976
|
this.agendaStore = agendaStore;
|
|
720
977
|
this.schedulerStore = schedulerStore;
|
|
721
978
|
this.now = now;
|
|
979
|
+
this.migrateLegacy = migrateLegacy !== false;
|
|
722
980
|
this.runtime = new SchedulerRuntime({
|
|
723
981
|
store: schedulerStore,
|
|
724
982
|
adapters: [
|
|
@@ -750,6 +1008,31 @@ export class AgendaSchedulerBridge {
|
|
|
750
1008
|
async runDue({ signal } = {}) {
|
|
751
1009
|
const results = [];
|
|
752
1010
|
const observedOccurrences = new Set();
|
|
1011
|
+
if (!signal?.aborted && this.migrateLegacy) {
|
|
1012
|
+
const sourceScope = {
|
|
1013
|
+
store: "agent-schedule",
|
|
1014
|
+
directory: canonicalSchedulerSourcePath(this.agendaStore.dir),
|
|
1015
|
+
};
|
|
1016
|
+
const candidates = this.agendaStore.list().filter((entry) => {
|
|
1017
|
+
const activeMigration =
|
|
1018
|
+
this.schedulerStore.getActiveDomainMigrationBySource({
|
|
1019
|
+
domain: "agenda",
|
|
1020
|
+
sourceScope,
|
|
1021
|
+
sourceId: entry.id,
|
|
1022
|
+
});
|
|
1023
|
+
if (entry.schedulerMigration) {
|
|
1024
|
+
return activeMigration?.state !== "retired";
|
|
1025
|
+
}
|
|
1026
|
+
return activeMigration?.state !== undefined;
|
|
1027
|
+
});
|
|
1028
|
+
for (const entry of candidates) {
|
|
1029
|
+
migrateAgendaSchedulerEntry({
|
|
1030
|
+
agendaStore: this.agendaStore,
|
|
1031
|
+
schedulerStore: this.schedulerStore,
|
|
1032
|
+
entry,
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
753
1036
|
const recovered = await this.runtime.runUntilIdle({
|
|
754
1037
|
limit: 10_000,
|
|
755
1038
|
signal,
|
|
@@ -772,9 +1055,9 @@ export class AgendaSchedulerBridge {
|
|
|
772
1055
|
|
|
773
1056
|
const now = normalizeEpochMs(Number(this.now()), "now");
|
|
774
1057
|
const due = [
|
|
775
|
-
...this.agendaStore.due("wakeup", now),
|
|
776
|
-
...this.agendaStore.due("cron", now),
|
|
777
|
-
...this.agendaStore.due("monitor", now),
|
|
1058
|
+
...this.agendaStore.due("wakeup", now, { schedulerMigration: true }),
|
|
1059
|
+
...this.agendaStore.due("cron", now, { schedulerMigration: true }),
|
|
1060
|
+
...this.agendaStore.due("monitor", now, { schedulerMigration: true }),
|
|
778
1061
|
];
|
|
779
1062
|
for (const entry of due) {
|
|
780
1063
|
const occurrence = enqueueAgendaEntry(this.schedulerStore, entry);
|
|
@@ -790,6 +1073,28 @@ export class AgendaSchedulerBridge {
|
|
|
790
1073
|
result,
|
|
791
1074
|
});
|
|
792
1075
|
}
|
|
1076
|
+
if (this.migrateLegacy) {
|
|
1077
|
+
const candidates = this.agendaStore
|
|
1078
|
+
.list()
|
|
1079
|
+
.filter(
|
|
1080
|
+
(entry) =>
|
|
1081
|
+
!entry.schedulerMigration &&
|
|
1082
|
+
[undefined, "succeeded"].includes(
|
|
1083
|
+
entry.schedulerExecution?.status,
|
|
1084
|
+
) &&
|
|
1085
|
+
!entry.executionLease &&
|
|
1086
|
+
((entry.kind === "wakeup" && entry.status === "pending") ||
|
|
1087
|
+
(["cron", "monitor"].includes(entry.kind) &&
|
|
1088
|
+
entry.status === "active")),
|
|
1089
|
+
);
|
|
1090
|
+
for (const entry of candidates) {
|
|
1091
|
+
migrateAgendaSchedulerEntry({
|
|
1092
|
+
agendaStore: this.agendaStore,
|
|
1093
|
+
schedulerStore: this.schedulerStore,
|
|
1094
|
+
entry,
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
793
1098
|
return results;
|
|
794
1099
|
}
|
|
795
1100
|
}
|