@hotmeshio/long-tail 0.10.7 → 0.10.9
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/build/api/escalations/bulk.js +7 -1
- package/build/api/escalations/helpers.d.ts +10 -1
- package/build/api/escalations/helpers.js +52 -12
- package/build/lib/events/matching.d.ts +10 -0
- package/build/lib/events/matching.js +14 -0
- package/build/lib/events/publish.d.ts +8 -2
- package/build/lib/events/publish.js +9 -2
- package/build/lib/events/socketio.d.ts +8 -2
- package/build/lib/events/socketio.js +36 -3
- package/build/lib/events/system-events.js +9 -1
- package/build/services/escalation/crud.js +40 -2
- package/build/services/orchestrator/condition.d.ts +1 -1
- package/build/services/orchestrator/condition.js +1 -1
- package/build/services/topics/system-topics.d.ts +0 -4
- package/build/services/topics/system-topics.js +57 -14
- package/build/types/events.d.ts +11 -3
- package/build/types/index.d.ts +1 -1
- package/dashboard/dist/assets/{AdminDashboard-CYlm0_J0.js → AdminDashboard-DWSYdAeW.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-CYlm0_J0.js.map → AdminDashboard-DWSYdAeW.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-BttOMcj_.js → AgentConfigPage-Dm6gL76m.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-BttOMcj_.js.map → AgentConfigPage-Dm6gL76m.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-D9JdkWV8.js → AgentDetailPage-D-Xbyrb6.js} +3 -3
- package/dashboard/dist/assets/AgentDetailPage-D-Xbyrb6.js.map +1 -0
- package/dashboard/dist/assets/{AgentsPage-AqGtEOL1.js → AgentsPage-DKaDRk-Y.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-AqGtEOL1.js.map → AgentsPage-DKaDRk-Y.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-rKbrcY8Y.js → AvailableEscalationsPage-B-aHvGKD.js} +2 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-B-aHvGKD.js.map +1 -0
- package/dashboard/dist/assets/{BotPicker-Bj4MB_so.js → BotPicker-DRv_orzI.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-Bj4MB_so.js.map → BotPicker-DRv_orzI.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-DzLP5-ad.js → CapabilitiesPage-DqRVzMol.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-DzLP5-ad.js.map → CapabilitiesPage-DqRVzMol.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-CReMhtzK.js → CollapsibleSection-D0psvw8i.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-CReMhtzK.js.map → CollapsibleSection-D0psvw8i.js.map} +1 -1
- package/dashboard/dist/assets/CountdownTimer-BhF3oqS8.js +2 -0
- package/dashboard/dist/assets/CountdownTimer-BhF3oqS8.js.map +1 -0
- package/dashboard/dist/assets/{CredentialsPage-D_2T6vSb.js → CredentialsPage-Axdci1z-.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-D_2T6vSb.js.map → CredentialsPage-Axdci1z-.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-DBmKrLvL.js → CronLabel-BjZ_wZA8.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-DBmKrLvL.js.map → CronLabel-BjZ_wZA8.js.map} +1 -1
- package/dashboard/dist/assets/CustomDurationPicker-CkUCMUfk.js +2 -0
- package/dashboard/dist/assets/CustomDurationPicker-CkUCMUfk.js.map +1 -0
- package/dashboard/dist/assets/{DropZone-BrnAkQxF.js → DropZone-_tmC3jEe.js} +2 -2
- package/dashboard/dist/assets/{DropZone-BrnAkQxF.js.map → DropZone-_tmC3jEe.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-C0LbM8o2.js → ElapsedCell-BE_CN5sP.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-C0LbM8o2.js.map → ElapsedCell-BE_CN5sP.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-CkEJnFKd.js → EscalationListSchemaPage-CgcVIiYR.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-CkEJnFKd.js.map → EscalationListSchemaPage-CgcVIiYR.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-CnlwGAIE.js → EscalationSchemaPage-BaAn1Hcr.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-CnlwGAIE.js.map → EscalationSchemaPage-BaAn1Hcr.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-DFM-f7do.js → EscalationsOverview-Dbq7tKzr.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-DFM-f7do.js.map → EscalationsOverview-Dbq7tKzr.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-Q3iICRf_.js → EventTable-0RUK9jqt.js} +2 -2
- package/dashboard/dist/assets/{EventTable-Q3iICRf_.js.map → EventTable-0RUK9jqt.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-B0taDH7I.js → FilterBar-B_dy2Jhj.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-B0taDH7I.js.map → FilterBar-B_dy2Jhj.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-B_P3pJeA.js → GraphInvokePage-CvLYp1nL.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-B_P3pJeA.js.map → GraphInvokePage-CvLYp1nL.js.map} +1 -1
- package/dashboard/dist/assets/HomePage-B6s1ZeyA.js +2 -0
- package/dashboard/dist/assets/HomePage-B6s1ZeyA.js.map +1 -0
- package/dashboard/dist/assets/{ListToolbar-ueCQtu5C.js → ListToolbar-DVhlAKZ3.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-ueCQtu5C.js.map → ListToolbar-DVhlAKZ3.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-DMaRUXnA.js → McpOverview-Ca8cpc8g.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-DMaRUXnA.js.map → McpOverview-Ca8cpc8g.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-D6YSD94n.js → McpQueryDetailPage-D0r2lyZg.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-D6YSD94n.js.map → McpQueryDetailPage-D0r2lyZg.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-CNGNB59o.js → McpQueryPage-DPP6BB3d.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-CNGNB59o.js.map → McpQueryPage-DPP6BB3d.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-CJ9hDTNs.js → McpRunDetailPage-C76mfUtG.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-CJ9hDTNs.js.map → McpRunDetailPage-C76mfUtG.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-_UaoIwzX.js → McpRunsPage-B43BqEyw.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-_UaoIwzX.js.map → McpRunsPage-B43BqEyw.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-DQGzN0Ph.js → NamespacePill-B5gHotsd.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-DQGzN0Ph.js.map → NamespacePill-B5gHotsd.js.map} +1 -1
- package/dashboard/dist/assets/OperationsPage-DbHzQCuE.js +2 -0
- package/dashboard/dist/assets/OperationsPage-DbHzQCuE.js.map +1 -0
- package/dashboard/dist/assets/OperatorDashboard-B70nS_Ah.js +2 -0
- package/dashboard/dist/assets/OperatorDashboard-B70nS_Ah.js.map +1 -0
- package/dashboard/dist/assets/{PageHeader-DlcE3U5L.js → PageHeader-DrbNMGxm.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-DlcE3U5L.js.map → PageHeader-DrbNMGxm.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-BMhnR3-9.js → PageHeaderWithStats-SbQkaQLG.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-BMhnR3-9.js.map → PageHeaderWithStats-SbQkaQLG.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-CxJ5BSDk.js → ProcessDetailPage-eLLUCWFf.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-CxJ5BSDk.js.map → ProcessDetailPage-eLLUCWFf.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-GQMOo5Wo.js → ProcessesListPage-Di0n8TR4.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-GQMOo5Wo.js.map → ProcessesListPage-Di0n8TR4.js.map} +1 -1
- package/dashboard/dist/assets/{RoleDetailPage-Bh5qdI0w.js → RoleDetailPage-Dhn9zU5l.js} +3 -3
- package/dashboard/dist/assets/{RoleDetailPage-Bh5qdI0w.js.map → RoleDetailPage-Dhn9zU5l.js.map} +1 -1
- package/dashboard/dist/assets/{RolePill-dzo14hB_.js → RolePill-Cz-AAWqA.js} +2 -2
- package/dashboard/dist/assets/{RolePill-dzo14hB_.js.map → RolePill-Cz-AAWqA.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-BIg3_Em6.js → RolesPage-BnAwjUiG.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-BIg3_Em6.js.map → RolesPage-BnAwjUiG.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-DQp_keSD.js → RunAsSelector-DFv0VNVZ.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-DQp_keSD.js.map → RunAsSelector-DFv0VNVZ.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-qLaLa33X.js → StickyPagination-D5zxe_l9.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-qLaLa33X.js.map → StickyPagination-D5zxe_l9.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-Bi37x95H.js → StreamMessageDetail-BmBfNSEr.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-Bi37x95H.js.map → StreamMessageDetail-BmBfNSEr.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-BdNhoiW8.js → SwimlaneTimeline-CA0TKDIi.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-BdNhoiW8.js.map → SwimlaneTimeline-CA0TKDIi.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-cyhTZTwe.js → TagInput-Bf9dZSG6.js} +2 -2
- package/dashboard/dist/assets/{TagInput-cyhTZTwe.js.map → TagInput-Bf9dZSG6.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-ngdXRgQp.js → TaskDetailPage-C15nADUW.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-ngdXRgQp.js.map → TaskDetailPage-C15nADUW.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-_zIpG4bG.js → TaskQueuePill-DfiBYQy2.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-_zIpG4bG.js.map → TaskQueuePill-DfiBYQy2.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-BIE7nrdE.js → TasksListPage-DQdAayqc.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-BIE7nrdE.js.map → TasksListPage-DQdAayqc.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-C6FZSNZp.js → TimeAgo-CvslqTB7.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-C6FZSNZp.js.map → TimeAgo-CvslqTB7.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-DI5zPUgV.js → TimestampCell-BZCQQONl.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-DI5zPUgV.js.map → TimestampCell-BZCQQONl.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-CKHYG6eV.js → ToolPill-gA4sXukc.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-CKHYG6eV.js.map → ToolPill-gA4sXukc.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-Dli94RPI.js → ToolTestPanel-BgLVc6R5.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-Dli94RPI.js.map → ToolTestPanel-BgLVc6R5.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-vPtXb7gD.js → TopicDetailPage-9A0aPb4t.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-vPtXb7gD.js.map → TopicDetailPage-9A0aPb4t.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-BwiEX0pU.js → TopicsPage-o0EZxKbR.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-BwiEX0pU.js.map → TopicsPage-o0EZxKbR.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-YozoXJA1.js → UserName-DKMLxBJ5.js} +2 -2
- package/dashboard/dist/assets/{UserName-YozoXJA1.js.map → UserName-DKMLxBJ5.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-Bce8g08l.js → WorkflowExecutionPage-C-snB_dD.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-Bce8g08l.js.map → WorkflowExecutionPage-C-snB_dD.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-DlSVXnnj.js → WorkflowPill-Djt2AtZk.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-DlSVXnnj.js.map → WorkflowPill-Djt2AtZk.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-DpVAH35I.js → WorkflowsDashboard-BRQmgsLR.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-DpVAH35I.js.map → WorkflowsDashboard-BRQmgsLR.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-Bp2pxXJO.js → WorkflowsOverview-DmMdIRHQ.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-Bp2pxXJO.js.map → WorkflowsOverview-DmMdIRHQ.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CL_kD0mX.js → YamlWorkflowDetailPage-Bj7QkCry.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CL_kD0mX.js.map → YamlWorkflowDetailPage-Bj7QkCry.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-Dtt3x3_T.js → YamlWorkflowsPage-BIi77mE0.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-Dtt3x3_T.js.map → YamlWorkflowsPage-BIi77mE0.js.map} +1 -1
- package/dashboard/dist/assets/{agents-xhtLVBwq.js → agents-EBIsjLCr.js} +2 -2
- package/dashboard/dist/assets/{agents-xhtLVBwq.js.map → agents-EBIsjLCr.js.map} +1 -1
- package/dashboard/dist/assets/{bots-DZ1MQUms.js → bots-BXzxybS6.js} +2 -2
- package/dashboard/dist/assets/{bots-DZ1MQUms.js.map → bots-BXzxybS6.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-B8j2h7Jn.js → capabilities-CnprG6q_.js} +2 -2
- package/dashboard/dist/assets/{capabilities-B8j2h7Jn.js.map → capabilities-CnprG6q_.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-DKijNA6h.js → controlplane-DiC0xtNq.js} +2 -2
- package/dashboard/dist/assets/{controlplane-DKijNA6h.js.map → controlplane-DiC0xtNq.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-DjoZ4dDb.js → escalation-columns-D0aYpJkF.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-DjoZ4dDb.js.map → escalation-columns-D0aYpJkF.js.map} +1 -1
- package/dashboard/dist/assets/index-B2iZG_HP.css +1 -0
- package/dashboard/dist/assets/{index-BCIJE--_.js → index-B6ldRx_s.js} +2 -2
- package/dashboard/dist/assets/{index-BCIJE--_.js.map → index-B6ldRx_s.js.map} +1 -1
- package/dashboard/dist/assets/{index-DrPWIFSv.js → index-BHAjQoOy.js} +2 -2
- package/dashboard/dist/assets/{index-DrPWIFSv.js.map → index-BHAjQoOy.js.map} +1 -1
- package/dashboard/dist/assets/{index-DcDEJ6b_.js → index-BzRXMicE.js} +2 -2
- package/dashboard/dist/assets/{index-DcDEJ6b_.js.map → index-BzRXMicE.js.map} +1 -1
- package/dashboard/dist/assets/{index-CMv6YMJY.js → index-C7KY8GTF.js} +2 -2
- package/dashboard/dist/assets/{index-CMv6YMJY.js.map → index-C7KY8GTF.js.map} +1 -1
- package/dashboard/dist/assets/index-CSTwyrwu.js +63 -0
- package/dashboard/dist/assets/index-CSTwyrwu.js.map +1 -0
- package/dashboard/dist/assets/{index-DYCCUmSM.js → index-CcMIca5t.js} +2 -2
- package/dashboard/dist/assets/{index-DYCCUmSM.js.map → index-CcMIca5t.js.map} +1 -1
- package/dashboard/dist/assets/{index-BqeQGQ4K.js → index-CjBdB8Ht.js} +2 -2
- package/dashboard/dist/assets/{index-BqeQGQ4K.js.map → index-CjBdB8Ht.js.map} +1 -1
- package/dashboard/dist/assets/{index-B0ktIiOY.js → index-D-7mT0ew.js} +2 -2
- package/dashboard/dist/assets/{index-B0ktIiOY.js.map → index-D-7mT0ew.js.map} +1 -1
- package/dashboard/dist/assets/{index-Cp1jJHm1.js → index-DDA7FvqT.js} +2 -2
- package/dashboard/dist/assets/{index-Cp1jJHm1.js.map → index-DDA7FvqT.js.map} +1 -1
- package/dashboard/dist/assets/index-DVmC_UfQ.js +5 -0
- package/dashboard/dist/assets/index-DVmC_UfQ.js.map +1 -0
- package/dashboard/dist/assets/{index-ChHD9p_I.js → index-Dht0ihGT.js} +2 -2
- package/dashboard/dist/assets/{index-ChHD9p_I.js.map → index-Dht0ihGT.js.map} +1 -1
- package/dashboard/dist/assets/{index-DWDEa8jS.js → index-gBnGEubX.js} +2 -2
- package/dashboard/dist/assets/{index-DWDEa8jS.js.map → index-gBnGEubX.js.map} +1 -1
- package/dashboard/dist/assets/{index-0SzWFShg.js → index-ovFEZ9SV.js} +2 -2
- package/dashboard/dist/assets/{index-0SzWFShg.js.map → index-ovFEZ9SV.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-Dl3cOfFR.js → knowledge-W5QSKkYQ.js} +2 -2
- package/dashboard/dist/assets/{knowledge-Dl3cOfFR.js.map → knowledge-W5QSKkYQ.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-BwjeqkHn.js → mcp-n877HyOj.js} +2 -2
- package/dashboard/dist/assets/{mcp-BwjeqkHn.js.map → mcp-n877HyOj.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-C1Rlt4az.js → mcp-query-C9kV4sUm.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-C1Rlt4az.js.map → mcp-query-C9kV4sUm.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-BGIUgIH_.js → pipelines-CBR68T8R.js} +2 -2
- package/dashboard/dist/assets/{pipelines-BGIUgIH_.js.map → pipelines-CBR68T8R.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-CnC1xEaD.js → tasks-DHpWqKMk.js} +2 -2
- package/dashboard/dist/assets/{tasks-CnC1xEaD.js.map → tasks-DHpWqKMk.js.map} +1 -1
- package/dashboard/dist/assets/{topics-C6EcHi07.js → topics-CaLtyqSh.js} +2 -2
- package/dashboard/dist/assets/{topics-C6EcHi07.js.map → topics-CaLtyqSh.js.map} +1 -1
- package/dashboard/dist/assets/useEventHooks-B8p56JlB.js +2 -0
- package/dashboard/dist/assets/useEventHooks-B8p56JlB.js.map +1 -0
- package/dashboard/dist/assets/{useNamespace-Ci_oA5Tq.js → useNamespace-ej71FCvu.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-Ci_oA5Tq.js.map → useNamespace-ej71FCvu.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-u8RUiMma.js → useYamlActivityEvents-DgpiFXib.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-u8RUiMma.js.map → useYamlActivityEvents-DgpiFXib.js.map} +1 -1
- package/dashboard/dist/assets/{users-DtiYvg8z.js → users-CHnjI_Ca.js} +2 -2
- package/dashboard/dist/assets/{users-DtiYvg8z.js.map → users-CHnjI_Ca.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-BE_WrH2z.js → vendor-icons-Bg6eJX4Z.js} +136 -141
- package/dashboard/dist/assets/vendor-icons-Bg6eJX4Z.js.map +1 -0
- package/dashboard/dist/assets/{workflows-BysPDsh9.js → workflows-DtnXUL0U.js} +2 -2
- package/dashboard/dist/assets/{workflows-BysPDsh9.js.map → workflows-DtnXUL0U.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-31qtxg5W.js → yaml-workflows-DDclYAID.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-31qtxg5W.js.map → yaml-workflows-DDclYAID.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/api/http/escalations.md +2 -2
- package/docs/api/sdk/escalations.md +2 -2
- package/docs/events.md +4 -2
- package/docs/hitl/escalation.md +2 -2
- package/docs/hitl/x-lt-embed.md +41 -12
- package/docs/hitl/x-lt-list-schema.md +26 -3
- package/package.json +1 -1
- package/dashboard/dist/assets/AgentDetailPage-D9JdkWV8.js.map +0 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-rKbrcY8Y.js.map +0 -1
- package/dashboard/dist/assets/CountdownTimer-Z8N8ccJ1.js +0 -2
- package/dashboard/dist/assets/CountdownTimer-Z8N8ccJ1.js.map +0 -1
- package/dashboard/dist/assets/CustomDurationPicker-BTmpAQOL.js +0 -2
- package/dashboard/dist/assets/CustomDurationPicker-BTmpAQOL.js.map +0 -1
- package/dashboard/dist/assets/HomePage-lu88PzQH.js +0 -2
- package/dashboard/dist/assets/HomePage-lu88PzQH.js.map +0 -1
- package/dashboard/dist/assets/OperationsPage-CTfwuWXR.js +0 -2
- package/dashboard/dist/assets/OperationsPage-CTfwuWXR.js.map +0 -1
- package/dashboard/dist/assets/OperatorDashboard-DMPJmgP_.js +0 -2
- package/dashboard/dist/assets/OperatorDashboard-DMPJmgP_.js.map +0 -1
- package/dashboard/dist/assets/index-C6UuVkz7.js +0 -63
- package/dashboard/dist/assets/index-C6UuVkz7.js.map +0 -1
- package/dashboard/dist/assets/index-Dh5Y3hq7.js +0 -5
- package/dashboard/dist/assets/index-Dh5Y3hq7.js.map +0 -1
- package/dashboard/dist/assets/index-WSGppNeK.css +0 -1
- package/dashboard/dist/assets/useEventHooks-Cyq4DiQA.js +0 -2
- package/dashboard/dist/assets/useEventHooks-Cyq4DiQA.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-BE_WrH2z.js.map +0 -1
|
@@ -166,7 +166,7 @@ async function bulkAssign(input, auth) {
|
|
|
166
166
|
}
|
|
167
167
|
const result = await escalationService.bulkAssignEscalationsByQuery({ role: query.role, facets: query.facets }, targetUserId, durationMinutes ?? 30);
|
|
168
168
|
if (result.assigned > 0)
|
|
169
|
-
(0, helpers_1.publishBulkClaimEvents)(result.ids, targetUserId);
|
|
169
|
+
(0, helpers_1.publishBulkClaimEvents)(result.ids, targetUserId, query.role);
|
|
170
170
|
return { status: 200, data: { assigned: result.assigned, skipped: 0 } };
|
|
171
171
|
}
|
|
172
172
|
if (!(0, helpers_1.validateIds)(ids)) {
|
|
@@ -215,7 +215,13 @@ async function bulkEscalate(input, auth) {
|
|
|
215
215
|
const perm = await (0, helpers_1.checkBulkPermission)(auth.userId, ids);
|
|
216
216
|
if (!perm.allowed)
|
|
217
217
|
return perm;
|
|
218
|
+
// Departing roles are read before the move so each reassignment can
|
|
219
|
+
// publish under BOTH queues — the one the row leaves and the one it
|
|
220
|
+
// joins (same contract as the single escalate path).
|
|
221
|
+
const beforeRows = await escalationService.getEscalationScopeRows(ids);
|
|
218
222
|
const updated = await escalationService.bulkEscalateToRole(ids, targetRole);
|
|
223
|
+
if (updated > 0)
|
|
224
|
+
(0, helpers_1.publishBulkReassignEvents)(beforeRows, targetRole);
|
|
219
225
|
return { status: 200, data: { updated } };
|
|
220
226
|
}
|
|
221
227
|
catch (err) {
|
|
@@ -141,4 +141,13 @@ export declare function resolveAssignee(assignee: string | undefined, auth: {
|
|
|
141
141
|
* Only adds the role if `provisionIfAbsent` declares it and caller has authority.
|
|
142
142
|
*/
|
|
143
143
|
export declare function ensureRoleMembership(userId: string, requiredRole: string, callerUserId: string, provisionIfAbsent?: ProvisionIfAbsent): Promise<boolean>;
|
|
144
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Publish `reassigned` for a bulk role move: every row publishes under its
|
|
146
|
+
* departing role AND the target role, so subscribers scoped to either queue
|
|
147
|
+
* observe the move. Rows already in the target role publish once.
|
|
148
|
+
*/
|
|
149
|
+
export declare function publishBulkReassignEvents(beforeRows: Array<{
|
|
150
|
+
id: string;
|
|
151
|
+
role: string;
|
|
152
|
+
}>, targetRole: string): void;
|
|
153
|
+
export declare function publishBulkClaimEvents(ids: string[], assignedTo: string, knownRole?: string): void;
|
|
@@ -44,6 +44,7 @@ exports.assertQueueManageAccess = assertQueueManageAccess;
|
|
|
44
44
|
exports.checkBulkPermission = checkBulkPermission;
|
|
45
45
|
exports.resolveAssignee = resolveAssignee;
|
|
46
46
|
exports.ensureRoleMembership = ensureRoleMembership;
|
|
47
|
+
exports.publishBulkReassignEvents = publishBulkReassignEvents;
|
|
47
48
|
exports.publishBulkClaimEvents = publishBulkClaimEvents;
|
|
48
49
|
const escalationService = __importStar(require("../../services/escalation"));
|
|
49
50
|
const userService = __importStar(require("../../services/user"));
|
|
@@ -254,17 +255,56 @@ async function ensureRoleMembership(userId, requiredRole, callerUserId, provisio
|
|
|
254
255
|
catch { /* already has it */ }
|
|
255
256
|
return true;
|
|
256
257
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
258
|
+
/**
|
|
259
|
+
* Publish `reassigned` for a bulk role move: every row publishes under its
|
|
260
|
+
* departing role AND the target role, so subscribers scoped to either queue
|
|
261
|
+
* observe the move. Rows already in the target role publish once.
|
|
262
|
+
*/
|
|
263
|
+
function publishBulkReassignEvents(beforeRows, targetRole) {
|
|
264
|
+
for (const row of beforeRows) {
|
|
265
|
+
const roles = row.role && row.role !== targetRole ? [row.role, targetRole] : [targetRole];
|
|
266
|
+
for (const role of roles) {
|
|
267
|
+
(0, publish_1.publishEscalationEvent)({
|
|
268
|
+
type: 'escalation.reassigned',
|
|
269
|
+
source: 'api',
|
|
270
|
+
workflowId: '',
|
|
271
|
+
workflowName: '',
|
|
272
|
+
taskQueue: '',
|
|
273
|
+
escalationId: row.id,
|
|
274
|
+
role,
|
|
275
|
+
status: 'pending',
|
|
276
|
+
data: { from_role: row.role, to_role: targetRole, bulk: true },
|
|
277
|
+
});
|
|
278
|
+
}
|
|
269
279
|
}
|
|
270
280
|
}
|
|
281
|
+
function publishBulkClaimEvents(ids, assignedTo, knownRole) {
|
|
282
|
+
// The claimed subject carries each row's role token. Query-form callers
|
|
283
|
+
// already know the single role; id-form callers resolve roles with one
|
|
284
|
+
// indexed read. Fire-and-forget, like every event publish.
|
|
285
|
+
void (async () => {
|
|
286
|
+
const roleById = new Map();
|
|
287
|
+
if (knownRole) {
|
|
288
|
+
for (const id of ids)
|
|
289
|
+
roleById.set(id, knownRole);
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
const rows = await escalationService.getEscalationScopeRows(ids);
|
|
293
|
+
for (const row of rows)
|
|
294
|
+
roleById.set(row.id, row.role);
|
|
295
|
+
}
|
|
296
|
+
for (const id of ids) {
|
|
297
|
+
(0, publish_1.publishEscalationEvent)({
|
|
298
|
+
type: 'escalation.claimed',
|
|
299
|
+
source: 'api',
|
|
300
|
+
workflowId: '',
|
|
301
|
+
workflowName: '',
|
|
302
|
+
taskQueue: '',
|
|
303
|
+
escalationId: id,
|
|
304
|
+
role: roleById.get(id) ?? '',
|
|
305
|
+
status: 'claimed',
|
|
306
|
+
data: { assigned_to: assignedTo, bulk: true },
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
})().catch(() => { });
|
|
310
|
+
}
|
|
@@ -10,4 +10,14 @@
|
|
|
10
10
|
* - `app.epic.apis.createorder.error` matches `app.epic.>`
|
|
11
11
|
* - `app.epic.apis.createorder.error` does NOT match `app.vendor.>`
|
|
12
12
|
*/
|
|
13
|
+
/**
|
|
14
|
+
* Make a value safe to embed as ONE token of a dot-delimited subject.
|
|
15
|
+
*
|
|
16
|
+
* Dots would splinter the token into extra subject levels; `*`, `>`, spaces,
|
|
17
|
+
* and other non-token characters would corrupt pattern matching (and are
|
|
18
|
+
* illegal in NATS subjects). Each run of unsafe characters collapses to a
|
|
19
|
+
* single `-`. An empty or missing value yields `none` so the subject always
|
|
20
|
+
* keeps its arity.
|
|
21
|
+
*/
|
|
22
|
+
export declare function sanitizeSubjectToken(value: string | null | undefined): string;
|
|
13
23
|
export declare function subjectMatchesPattern(subject: string, pattern: string): boolean;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sanitizeSubjectToken = sanitizeSubjectToken;
|
|
3
4
|
exports.subjectMatchesPattern = subjectMatchesPattern;
|
|
4
5
|
/**
|
|
5
6
|
* Match a dot-delimited subject against a pattern with NATS-style wildcards.
|
|
@@ -13,6 +14,19 @@ exports.subjectMatchesPattern = subjectMatchesPattern;
|
|
|
13
14
|
* - `app.epic.apis.createorder.error` matches `app.epic.>`
|
|
14
15
|
* - `app.epic.apis.createorder.error` does NOT match `app.vendor.>`
|
|
15
16
|
*/
|
|
17
|
+
/**
|
|
18
|
+
* Make a value safe to embed as ONE token of a dot-delimited subject.
|
|
19
|
+
*
|
|
20
|
+
* Dots would splinter the token into extra subject levels; `*`, `>`, spaces,
|
|
21
|
+
* and other non-token characters would corrupt pattern matching (and are
|
|
22
|
+
* illegal in NATS subjects). Each run of unsafe characters collapses to a
|
|
23
|
+
* single `-`. An empty or missing value yields `none` so the subject always
|
|
24
|
+
* keeps its arity.
|
|
25
|
+
*/
|
|
26
|
+
function sanitizeSubjectToken(value) {
|
|
27
|
+
const cleaned = (value ?? '').replace(/[^A-Za-z0-9_-]+/g, '-').replace(/^-+|-+$/g, '');
|
|
28
|
+
return cleaned || 'none';
|
|
29
|
+
}
|
|
16
30
|
function subjectMatchesPattern(subject, pattern) {
|
|
17
31
|
if (pattern === '*')
|
|
18
32
|
return true;
|
|
@@ -32,16 +32,22 @@ export declare function publishTaskEvent(params: {
|
|
|
32
32
|
}): Promise<void>;
|
|
33
33
|
/**
|
|
34
34
|
* Publish an escalation lifecycle event.
|
|
35
|
-
* Subject: system.escalation.{escalationId}.{action}
|
|
35
|
+
* Subject: system.escalation.{role}.{escalationId}.{action}
|
|
36
|
+
*
|
|
37
|
+
* The role token makes the queue the organizing level of the hierarchy:
|
|
38
|
+
* subscribers scope to one role (`system.escalation.{role}.>`), one verb
|
|
39
|
+
* across roles (`system.escalation.*.*.created`), or one item regardless of
|
|
40
|
+
* role hops (`system.escalation.*.{id}.>`).
|
|
36
41
|
*/
|
|
37
42
|
export declare function publishEscalationEvent(params: {
|
|
38
|
-
type: 'escalation.created' | 'escalation.resolved' | 'escalation.claimed' | 'escalation.released' | 'escalation.cancelled';
|
|
43
|
+
type: 'escalation.created' | 'escalation.resolved' | 'escalation.claimed' | 'escalation.released' | 'escalation.cancelled' | 'escalation.reassigned';
|
|
39
44
|
source: string;
|
|
40
45
|
workflowId: string;
|
|
41
46
|
workflowName: string;
|
|
42
47
|
taskQueue: string;
|
|
43
48
|
taskId?: string;
|
|
44
49
|
escalationId: string;
|
|
50
|
+
role: string;
|
|
45
51
|
originId?: string;
|
|
46
52
|
status: string;
|
|
47
53
|
data?: Record<string, any>;
|
|
@@ -9,6 +9,7 @@ exports.publishFileEvent = publishFileEvent;
|
|
|
9
9
|
exports.publishAgentEvent = publishAgentEvent;
|
|
10
10
|
exports.publishWorkflowEvent = publishWorkflowEvent;
|
|
11
11
|
const index_1 = require("./index");
|
|
12
|
+
const matching_1 = require("./matching");
|
|
12
13
|
const logger_1 = require("../logger");
|
|
13
14
|
/**
|
|
14
15
|
* Fire-and-forget publish helper. Swallows errors (best-effort).
|
|
@@ -62,13 +63,19 @@ function publishTaskEvent(params) {
|
|
|
62
63
|
}
|
|
63
64
|
/**
|
|
64
65
|
* Publish an escalation lifecycle event.
|
|
65
|
-
* Subject: system.escalation.{escalationId}.{action}
|
|
66
|
+
* Subject: system.escalation.{role}.{escalationId}.{action}
|
|
67
|
+
*
|
|
68
|
+
* The role token makes the queue the organizing level of the hierarchy:
|
|
69
|
+
* subscribers scope to one role (`system.escalation.{role}.>`), one verb
|
|
70
|
+
* across roles (`system.escalation.*.*.created`), or one item regardless of
|
|
71
|
+
* role hops (`system.escalation.*.{id}.>`).
|
|
66
72
|
*/
|
|
67
73
|
function publishEscalationEvent(params) {
|
|
68
74
|
const action = params.type.split('.')[1];
|
|
69
75
|
return fireAndForget({
|
|
70
|
-
type: `system.escalation.${params.escalationId}.${action}`,
|
|
76
|
+
type: `system.escalation.${(0, matching_1.sanitizeSubjectToken)(params.role)}.${params.escalationId}.${action}`,
|
|
71
77
|
source: params.source,
|
|
78
|
+
role: params.role,
|
|
72
79
|
workflowId: params.workflowId,
|
|
73
80
|
workflowName: params.workflowName,
|
|
74
81
|
taskQueue: params.taskQueue,
|
|
@@ -8,8 +8,14 @@ export type SocketIOAuthenticator = (token: string) => boolean | Promise<boolean
|
|
|
8
8
|
/**
|
|
9
9
|
* Socket.IO event adapter for browser clients.
|
|
10
10
|
*
|
|
11
|
-
* Publishes LTEvent payloads to
|
|
12
|
-
*
|
|
11
|
+
* Publishes LTEvent payloads to connected Socket.IO clients on channels
|
|
12
|
+
* following the pattern: `lt.events.{event.type}`.
|
|
13
|
+
*
|
|
14
|
+
* Delivery is scoped per socket: a client registers NATS-style subject
|
|
15
|
+
* patterns with `lt.subscribe` / `lt.unsubscribe` messages and receives only
|
|
16
|
+
* matching events — the server filters, the wire carries only what the page
|
|
17
|
+
* asked for. A socket that never registers a pattern receives every event
|
|
18
|
+
* (the broadcast contract external consumers may rely on).
|
|
13
19
|
*
|
|
14
20
|
* The HTTP server must be attached via `attachServer()` before
|
|
15
21
|
* `connect()` is called. The startup flow handles this automatically
|
|
@@ -3,11 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.SocketIOEventAdapter = void 0;
|
|
4
4
|
const socket_io_1 = require("socket.io");
|
|
5
5
|
const logger_1 = require("../logger");
|
|
6
|
+
const matching_1 = require("./matching");
|
|
6
7
|
/**
|
|
7
8
|
* Socket.IO event adapter for browser clients.
|
|
8
9
|
*
|
|
9
|
-
* Publishes LTEvent payloads to
|
|
10
|
-
*
|
|
10
|
+
* Publishes LTEvent payloads to connected Socket.IO clients on channels
|
|
11
|
+
* following the pattern: `lt.events.{event.type}`.
|
|
12
|
+
*
|
|
13
|
+
* Delivery is scoped per socket: a client registers NATS-style subject
|
|
14
|
+
* patterns with `lt.subscribe` / `lt.unsubscribe` messages and receives only
|
|
15
|
+
* matching events — the server filters, the wire carries only what the page
|
|
16
|
+
* asked for. A socket that never registers a pattern receives every event
|
|
17
|
+
* (the broadcast contract external consumers may rely on).
|
|
11
18
|
*
|
|
12
19
|
* The HTTP server must be attached via `attachServer()` before
|
|
13
20
|
* `connect()` is called. The startup flow handles this automatically
|
|
@@ -75,6 +82,19 @@ class SocketIOEventAdapter {
|
|
|
75
82
|
}
|
|
76
83
|
this.io.on('connection', (socket) => {
|
|
77
84
|
logger_1.loggerRegistry.info(`[lt-events:socketio] client connected (${socket.id})`);
|
|
85
|
+
// Per-socket subject-pattern scope. Registering the first pattern
|
|
86
|
+
// switches the socket from broadcast to scoped delivery.
|
|
87
|
+
const patterns = new Set();
|
|
88
|
+
socket.data.ltPatterns = patterns;
|
|
89
|
+
socket.on('lt.subscribe', (pattern) => {
|
|
90
|
+
if (typeof pattern === 'string' && pattern.length > 0 && pattern.length <= 256) {
|
|
91
|
+
patterns.add(pattern);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
socket.on('lt.unsubscribe', (pattern) => {
|
|
95
|
+
if (typeof pattern === 'string')
|
|
96
|
+
patterns.delete(pattern);
|
|
97
|
+
});
|
|
78
98
|
socket.on('disconnect', () => {
|
|
79
99
|
logger_1.loggerRegistry.debug(`[lt-events:socketio] client disconnected (${socket.id})`);
|
|
80
100
|
});
|
|
@@ -85,7 +105,20 @@ class SocketIOEventAdapter {
|
|
|
85
105
|
if (!this.io)
|
|
86
106
|
return;
|
|
87
107
|
const channel = `lt.events.${event.type}`;
|
|
88
|
-
this.io.
|
|
108
|
+
for (const socket of this.io.of('/').sockets.values()) {
|
|
109
|
+
const patterns = socket.data.ltPatterns;
|
|
110
|
+
if (!patterns || patterns.size === 0) {
|
|
111
|
+
// Legacy scope: a socket with no registered patterns gets everything.
|
|
112
|
+
socket.emit(channel, event);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
for (const pattern of patterns) {
|
|
116
|
+
if ((0, matching_1.subjectMatchesPattern)(channel, pattern)) {
|
|
117
|
+
socket.emit(channel, event);
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
89
122
|
}
|
|
90
123
|
async disconnect() {
|
|
91
124
|
if (this.io) {
|
|
@@ -4,6 +4,7 @@ exports.systemEventsConfig = void 0;
|
|
|
4
4
|
exports.mapSystemEvent = mapSystemEvent;
|
|
5
5
|
exports.onSystemEvent = onSystemEvent;
|
|
6
6
|
const index_1 = require("./index");
|
|
7
|
+
const matching_1 = require("./matching");
|
|
7
8
|
/** Verb → long-tail event status, matching the manual publishEscalationEvent convention. */
|
|
8
9
|
const ESCALATION_STATUS_BY_VERB = {
|
|
9
10
|
created: 'pending',
|
|
@@ -27,9 +28,16 @@ function mapSystemEvent(event) {
|
|
|
27
28
|
if (domain === 'escalation') {
|
|
28
29
|
const row = (event.data ?? {});
|
|
29
30
|
const verb = segments[3] ?? '';
|
|
31
|
+
// The SDK forms `system.escalation.{id}.{verb}`; long-tail's canonical
|
|
32
|
+
// subject carries the role as the organizing token. The committed row
|
|
33
|
+
// rides in `data`, so the role is lifted from it and the subject is
|
|
34
|
+
// rewritten to `system.escalation.{role}.{id}.{verb}` — the same shape
|
|
35
|
+
// publishEscalationEvent produces for the service-mediated path.
|
|
36
|
+
const role = row.role || undefined;
|
|
30
37
|
return {
|
|
31
|
-
type:
|
|
38
|
+
type: `system.escalation.${(0, matching_1.sanitizeSubjectToken)(role)}.${segments[2]}.${verb}`,
|
|
32
39
|
source: 'sdk',
|
|
40
|
+
role,
|
|
33
41
|
workflowId: row.workflow_id || event.workflow_id || undefined,
|
|
34
42
|
workflowName: row.workflow_type || undefined,
|
|
35
43
|
taskQueue: row.task_queue || undefined,
|
|
@@ -74,6 +74,7 @@ async function createEscalation(input) {
|
|
|
74
74
|
workflowName: escalation.workflow_type || '',
|
|
75
75
|
taskQueue: escalation.task_queue || '',
|
|
76
76
|
escalationId: escalation.id,
|
|
77
|
+
role: escalation.role,
|
|
77
78
|
status: 'pending',
|
|
78
79
|
data: { type: input.type, role: input.role },
|
|
79
80
|
});
|
|
@@ -97,6 +98,7 @@ async function claimEscalation(id, userId, durationMinutes = 30) {
|
|
|
97
98
|
workflowName: escalation.workflow_type || '',
|
|
98
99
|
taskQueue: escalation.task_queue || '',
|
|
99
100
|
escalationId: escalation.id,
|
|
101
|
+
role: escalation.role,
|
|
100
102
|
status: 'claimed',
|
|
101
103
|
data: { assigned_to: userId },
|
|
102
104
|
});
|
|
@@ -137,6 +139,7 @@ async function resolveEscalation(id, resolverPayload, metadata, assertClaim, res
|
|
|
137
139
|
workflowName: escalation.workflow_type || '',
|
|
138
140
|
taskQueue: escalation.task_queue || '',
|
|
139
141
|
escalationId: escalation.id,
|
|
142
|
+
role: escalation.role,
|
|
140
143
|
status: 'resolved',
|
|
141
144
|
data: {},
|
|
142
145
|
});
|
|
@@ -170,6 +173,7 @@ async function resolveEscalationsByIds(ids, resolverPayload, metadata) {
|
|
|
170
173
|
workflowName: escalation.workflow_type || '',
|
|
171
174
|
taskQueue: escalation.task_queue || '',
|
|
172
175
|
escalationId: escalation.id,
|
|
176
|
+
role: escalation.role,
|
|
173
177
|
status: 'resolved',
|
|
174
178
|
data: {},
|
|
175
179
|
});
|
|
@@ -209,6 +213,7 @@ async function resolveEscalationsAllOrNone(items, metadata, assertAssignee, reso
|
|
|
209
213
|
workflowName: escalation.workflow_type || '',
|
|
210
214
|
taskQueue: escalation.task_queue || '',
|
|
211
215
|
escalationId: escalation.id,
|
|
216
|
+
role: escalation.role,
|
|
212
217
|
status: 'resolved',
|
|
213
218
|
data: {},
|
|
214
219
|
});
|
|
@@ -276,6 +281,7 @@ async function cancelEscalation(id) {
|
|
|
276
281
|
workflowName: cancelled.workflow_type || '',
|
|
277
282
|
taskQueue: cancelled.task_queue || '',
|
|
278
283
|
escalationId: cancelled.id,
|
|
284
|
+
role: cancelled.role,
|
|
279
285
|
status: 'cancelled',
|
|
280
286
|
data: { reason: 'workflow_terminated' },
|
|
281
287
|
});
|
|
@@ -335,6 +341,7 @@ async function releaseEscalation(id, userId) {
|
|
|
335
341
|
workflowName: released.workflow_type || '',
|
|
336
342
|
taskQueue: released.task_queue || '',
|
|
337
343
|
escalationId: released.id,
|
|
344
|
+
role: released.role,
|
|
338
345
|
status: 'released',
|
|
339
346
|
data: { released_by: userId },
|
|
340
347
|
});
|
|
@@ -358,8 +365,36 @@ async function releaseExpiredClaims() {
|
|
|
358
365
|
*/
|
|
359
366
|
async function escalateToRole(id, targetRole) {
|
|
360
367
|
const client = await (0, client_1.escalations)();
|
|
368
|
+
// The departing role is read before the move: the returned entry already
|
|
369
|
+
// carries the target role, and role-scoped subscribers of the OLD queue
|
|
370
|
+
// must see the item leave just as the new queue sees it arrive.
|
|
371
|
+
const before = await client.get(id);
|
|
372
|
+
const fromRole = before?.role ?? null;
|
|
361
373
|
const entry = await client.escalateToRole({ id, targetRole });
|
|
362
|
-
|
|
374
|
+
if (!entry)
|
|
375
|
+
return null;
|
|
376
|
+
const escalation = (0, map_1.toEscalationRecord)(entry);
|
|
377
|
+
// One reassignment, two subjects: the same event publishes under the
|
|
378
|
+
// departing role and the arriving role, so a subscriber scoped to either
|
|
379
|
+
// queue observes the move. `data` names both ends for consumers that
|
|
380
|
+
// only see one side.
|
|
381
|
+
const rolesToNotify = fromRole && fromRole !== escalation.role
|
|
382
|
+
? [fromRole, escalation.role]
|
|
383
|
+
: [escalation.role];
|
|
384
|
+
for (const role of rolesToNotify) {
|
|
385
|
+
publishEscalationChange({
|
|
386
|
+
type: 'escalation.reassigned',
|
|
387
|
+
source: 'service',
|
|
388
|
+
workflowId: escalation.workflow_id || '',
|
|
389
|
+
workflowName: escalation.workflow_type || '',
|
|
390
|
+
taskQueue: escalation.task_queue || '',
|
|
391
|
+
escalationId: escalation.id,
|
|
392
|
+
role,
|
|
393
|
+
status: 'pending',
|
|
394
|
+
data: { from_role: fromRole, to_role: escalation.role },
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
return escalation;
|
|
363
398
|
}
|
|
364
399
|
async function getEscalation(id) {
|
|
365
400
|
const client = await (0, client_1.escalations)();
|
|
@@ -402,7 +437,7 @@ async function cancelEscalationsByWorkflowId(workflowId) {
|
|
|
402
437
|
SET status = 'cancelled', updated_at = NOW()
|
|
403
438
|
WHERE workflow_id = $1
|
|
404
439
|
AND status = 'pending'
|
|
405
|
-
RETURNING id, workflow_id, workflow_type, task_queue`, [workflowId]);
|
|
440
|
+
RETURNING id, workflow_id, workflow_type, task_queue, role`, [workflowId]);
|
|
406
441
|
for (const row of rows) {
|
|
407
442
|
publishEscalationChange({
|
|
408
443
|
type: 'escalation.cancelled',
|
|
@@ -411,6 +446,7 @@ async function cancelEscalationsByWorkflowId(workflowId) {
|
|
|
411
446
|
workflowName: row.workflow_type || '',
|
|
412
447
|
taskQueue: row.task_queue || '',
|
|
413
448
|
escalationId: row.id,
|
|
449
|
+
role: row.role || '',
|
|
414
450
|
status: 'cancelled',
|
|
415
451
|
data: { reason: 'workflow_terminated' },
|
|
416
452
|
});
|
|
@@ -498,6 +534,7 @@ async function claimByMetadata(key, value, userId, durationMinutes = 30, metadat
|
|
|
498
534
|
workflowName: escalation.workflow_type || '',
|
|
499
535
|
taskQueue: escalation.task_queue || '',
|
|
500
536
|
escalationId: escalation.id,
|
|
537
|
+
role: escalation.role,
|
|
501
538
|
status: 'claimed',
|
|
502
539
|
data: { assigned_to: userId },
|
|
503
540
|
});
|
|
@@ -556,6 +593,7 @@ async function resolveByMetadataAtomic(key, value, userId, resolverPayload, meta
|
|
|
556
593
|
workflowName: escalation.workflow_type || '',
|
|
557
594
|
taskQueue: escalation.task_queue || '',
|
|
558
595
|
escalationId: escalation.id,
|
|
596
|
+
role: escalation.role,
|
|
559
597
|
status: 'resolved',
|
|
560
598
|
data: { resolved_by: userId },
|
|
561
599
|
});
|
|
@@ -21,7 +21,7 @@ export type ConditionEscalationConfig = Types.ConditionQueueConfig & {
|
|
|
21
21
|
* written inside this workflow's Leg1 checkpoint (one commit, crash-safe — no
|
|
22
22
|
* separate create activity, no enrich). `signal_key` is the signal id, so the
|
|
23
23
|
* dashboard resolve endpoint (Path 0), `resolveEscalationBySignalKey`, and any
|
|
24
|
-
* webhook resume the SAME job in place. `system.escalation.{id}.created` fires
|
|
24
|
+
* webhook resume the SAME job in place. `system.escalation.{role}.{id}.created` fires
|
|
25
25
|
* from the engine automatically.
|
|
26
26
|
*
|
|
27
27
|
* ```typescript
|
|
@@ -60,7 +60,7 @@ function toEngineConfig(escalation) {
|
|
|
60
60
|
* written inside this workflow's Leg1 checkpoint (one commit, crash-safe — no
|
|
61
61
|
* separate create activity, no enrich). `signal_key` is the signal id, so the
|
|
62
62
|
* dashboard resolve endpoint (Path 0), `resolveEscalationBySignalKey`, and any
|
|
63
|
-
* webhook resume the SAME job in place. `system.escalation.{id}.created` fires
|
|
63
|
+
* webhook resume the SAME job in place. `system.escalation.{role}.{id}.created` fires
|
|
64
64
|
* from the engine automatically.
|
|
65
65
|
*
|
|
66
66
|
* ```typescript
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import type { LTTopicConfig } from '../../types';
|
|
2
|
-
/**
|
|
3
|
-
* Seed all 22 built-in system topics into the catalog.
|
|
4
|
-
* Called once at startup after migrations.
|
|
5
|
-
*/
|
|
6
2
|
export declare function seedSystemTopics(): Promise<void>;
|
|
7
3
|
/**
|
|
8
4
|
* Seed user-declared topics from startConfig.topics[].
|
|
@@ -12,6 +12,7 @@ const WORKFLOW_CONTEXT_PROPS = {
|
|
|
12
12
|
originId: { type: 'string', description: 'Root process lineage ID' },
|
|
13
13
|
};
|
|
14
14
|
const STATUS_FIELD = { type: 'string', description: 'Status after this event' };
|
|
15
|
+
const ROLE_FIELD = { type: 'string', description: 'Escalation role (the queue) — also the third subject token' };
|
|
15
16
|
function objectSchema(properties) {
|
|
16
17
|
return { type: 'object', properties };
|
|
17
18
|
}
|
|
@@ -83,37 +84,64 @@ const SYSTEM_TOPICS = [
|
|
|
83
84
|
example_payload: { workflowId: 'wf-abc', workflowName: 'processOrder', status: 'failed' },
|
|
84
85
|
tags: ['lifecycle', 'error'],
|
|
85
86
|
},
|
|
86
|
-
// Escalation lifecycle
|
|
87
|
+
// Escalation lifecycle — subjects are `system.escalation.{role}.{id}.{verb}`.
|
|
88
|
+
// The role token is the organizing level: subscribe to one queue with
|
|
89
|
+
// `system.escalation.{role}.>`, one verb across queues with
|
|
90
|
+
// `system.escalation.*.*.{verb}`, or one item with `system.escalation.*.{id}.>`.
|
|
87
91
|
{
|
|
88
|
-
topic: 'system.escalation
|
|
92
|
+
topic: 'system.escalation.*.*.created',
|
|
89
93
|
description: 'An escalation has been created.',
|
|
90
94
|
category: 'escalation',
|
|
91
|
-
payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, status: STATUS_FIELD, data: { type: 'object' } }),
|
|
92
|
-
example_payload: { escalationId: 'esc-001', status: 'pending', workflowName: 'processOrder' },
|
|
95
|
+
payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, role: ROLE_FIELD, status: STATUS_FIELD, data: { type: 'object' } }),
|
|
96
|
+
example_payload: { escalationId: 'esc-001', role: 'order-review', status: 'pending', workflowName: 'processOrder' },
|
|
93
97
|
tags: ['lifecycle', 'hitl'],
|
|
94
98
|
},
|
|
95
99
|
{
|
|
96
|
-
topic: 'system.escalation
|
|
100
|
+
topic: 'system.escalation.*.*.resolved',
|
|
97
101
|
description: 'An escalation has been resolved.',
|
|
98
102
|
category: 'escalation',
|
|
99
|
-
payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, status: STATUS_FIELD, data: { type: 'object' } }),
|
|
100
|
-
example_payload: { escalationId: 'esc-001', status: 'resolved', workflowName: 'processOrder' },
|
|
103
|
+
payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, role: ROLE_FIELD, status: STATUS_FIELD, data: { type: 'object' } }),
|
|
104
|
+
example_payload: { escalationId: 'esc-001', role: 'order-review', status: 'resolved', workflowName: 'processOrder' },
|
|
101
105
|
tags: ['lifecycle', 'hitl'],
|
|
102
106
|
},
|
|
103
107
|
{
|
|
104
|
-
topic: 'system.escalation
|
|
108
|
+
topic: 'system.escalation.*.*.claimed',
|
|
105
109
|
description: 'An escalation has been claimed.',
|
|
106
110
|
category: 'escalation',
|
|
107
|
-
payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, status: STATUS_FIELD }),
|
|
108
|
-
example_payload: { escalationId: 'esc-001', status: 'claimed' },
|
|
111
|
+
payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, role: ROLE_FIELD, status: STATUS_FIELD }),
|
|
112
|
+
example_payload: { escalationId: 'esc-001', role: 'order-review', status: 'claimed' },
|
|
109
113
|
tags: ['lifecycle', 'hitl'],
|
|
110
114
|
},
|
|
111
115
|
{
|
|
112
|
-
topic: 'system.escalation
|
|
116
|
+
topic: 'system.escalation.*.*.released',
|
|
113
117
|
description: 'An escalation has been returned to the queue.',
|
|
114
118
|
category: 'escalation',
|
|
115
|
-
payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, status: STATUS_FIELD }),
|
|
116
|
-
example_payload: { escalationId: 'esc-001', status: 'pending' },
|
|
119
|
+
payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, role: ROLE_FIELD, status: STATUS_FIELD }),
|
|
120
|
+
example_payload: { escalationId: 'esc-001', role: 'order-review', status: 'pending' },
|
|
121
|
+
tags: ['lifecycle', 'hitl'],
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
topic: 'system.escalation.*.*.cancelled',
|
|
125
|
+
description: 'An escalation has been cancelled.',
|
|
126
|
+
category: 'escalation',
|
|
127
|
+
payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, role: ROLE_FIELD, status: STATUS_FIELD, data: { type: 'object' } }),
|
|
128
|
+
example_payload: { escalationId: 'esc-001', role: 'order-review', status: 'cancelled' },
|
|
129
|
+
tags: ['lifecycle', 'hitl'],
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
topic: 'system.escalation.*.*.reassigned',
|
|
133
|
+
description: 'An escalation has moved to a different role. Publishes under both the departing and arriving role.',
|
|
134
|
+
category: 'escalation',
|
|
135
|
+
payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, role: ROLE_FIELD, status: STATUS_FIELD, data: { type: 'object', description: 'from_role and to_role' } }),
|
|
136
|
+
example_payload: { escalationId: 'esc-001', role: 'order-manager', status: 'pending', data: { from_role: 'order-review', to_role: 'order-manager' } },
|
|
137
|
+
tags: ['lifecycle', 'hitl'],
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
topic: 'system.escalation.*.*.expired',
|
|
141
|
+
description: 'A waiting escalation hit its SLA timeout and the engine transitioned it.',
|
|
142
|
+
category: 'escalation',
|
|
143
|
+
payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, role: ROLE_FIELD, status: STATUS_FIELD, data: { type: 'object' } }),
|
|
144
|
+
example_payload: { escalationId: 'esc-001', role: 'order-review', status: 'expired' },
|
|
117
145
|
tags: ['lifecycle', 'hitl'],
|
|
118
146
|
},
|
|
119
147
|
// Activity lifecycle
|
|
@@ -247,9 +275,18 @@ function inferCategory(topic) {
|
|
|
247
275
|
return topic.split('.')[0];
|
|
248
276
|
}
|
|
249
277
|
/**
|
|
250
|
-
* Seed
|
|
278
|
+
* Seed the built-in system topics into the catalog.
|
|
251
279
|
* Called once at startup after migrations.
|
|
252
280
|
*/
|
|
281
|
+
// Catalog names no longer published. Escalation subjects carry the role token
|
|
282
|
+
// (`system.escalation.{role}.{id}.{verb}`), so the roleless names are retired
|
|
283
|
+
// from the catalog at seed time.
|
|
284
|
+
const RETIRED_TOPICS = [
|
|
285
|
+
'system.escalation.*.created',
|
|
286
|
+
'system.escalation.*.resolved',
|
|
287
|
+
'system.escalation.*.claimed',
|
|
288
|
+
'system.escalation.*.released',
|
|
289
|
+
];
|
|
253
290
|
async function seedSystemTopics() {
|
|
254
291
|
for (const def of SYSTEM_TOPICS) {
|
|
255
292
|
try {
|
|
@@ -268,6 +305,12 @@ async function seedSystemTopics() {
|
|
|
268
305
|
logger_1.loggerRegistry.warn(`[long-tail] topic seed failed for ${def.topic}: ${err.message}`);
|
|
269
306
|
}
|
|
270
307
|
}
|
|
308
|
+
for (const retired of RETIRED_TOPICS) {
|
|
309
|
+
try {
|
|
310
|
+
await (0, index_1.deleteTopic)(retired);
|
|
311
|
+
}
|
|
312
|
+
catch { /* absent on a fresh catalog */ }
|
|
313
|
+
}
|
|
271
314
|
}
|
|
272
315
|
/**
|
|
273
316
|
* Seed user-declared topics from startConfig.topics[].
|
package/build/types/events.d.ts
CHANGED
|
@@ -4,16 +4,21 @@ import type { LTMilestone } from './task';
|
|
|
4
4
|
*
|
|
5
5
|
* System events use structured subjects with embedded resource IDs:
|
|
6
6
|
* `system.workflow.{workflowId}.completed`
|
|
7
|
-
* `system.escalation.{escalationId}.claimed`
|
|
7
|
+
* `system.escalation.{role}.{escalationId}.claimed`
|
|
8
8
|
* `system.activity.{workflowId}.{activityName}.failed`
|
|
9
9
|
*
|
|
10
|
+
* Escalation subjects carry the role as the organizing token — the queue is
|
|
11
|
+
* the unit of subscription. Scope to a role (`system.escalation.{role}.>`),
|
|
12
|
+
* a verb across roles (`system.escalation.*.*.created`), or one item across
|
|
13
|
+
* role hops (`system.escalation.*.{id}.>`).
|
|
14
|
+
*
|
|
10
15
|
* On the wire (NATS): `lt.events.system.workflow.abc123.completed`
|
|
11
16
|
* Dashboard subscribes: `lt.events.system.>` for all system events,
|
|
12
17
|
* or `lt.events.system.workflow.abc123.>` for a specific workflow.
|
|
13
18
|
*
|
|
14
19
|
* The `*` segments in these patterns are replaced with actual IDs at publish time.
|
|
15
20
|
*/
|
|
16
|
-
export type LTSystemEventPattern = `system.task.${string}.created` | `system.task.${string}.started` | `system.task.${string}.completed` | `system.task.${string}.escalated` | `system.task.${string}.failed` | `system.escalation.${string}.created` | `system.escalation.${string}.resolved` | `system.escalation.${string}.claimed` | `system.escalation.${string}.released` | `system.workflow.${string}.started` | `system.workflow.${string}.completed` | `system.workflow.${string}.failed` | `system.activity.${string}.${string}.started` | `system.activity.${string}.${string}.completed` | `system.activity.${string}.${string}.failed` | `system.knowledge.${string}.stored` | `system.knowledge.${string}.deleted` | 'system.file.stored' | 'system.file.deleted' | `system.agent.${string}.started` | `system.agent.${string}.completed` | `system.agent.${string}.failed` | `system.agent.${string}.status_changed` | `system.agent.${string}.triggers_changed` | `system.milestone.${string}`;
|
|
21
|
+
export type LTSystemEventPattern = `system.task.${string}.created` | `system.task.${string}.started` | `system.task.${string}.completed` | `system.task.${string}.escalated` | `system.task.${string}.failed` | `system.escalation.${string}.${string}.created` | `system.escalation.${string}.${string}.resolved` | `system.escalation.${string}.${string}.claimed` | `system.escalation.${string}.${string}.released` | `system.escalation.${string}.${string}.cancelled` | `system.escalation.${string}.${string}.reassigned` | `system.escalation.${string}.${string}.expired` | `system.workflow.${string}.started` | `system.workflow.${string}.completed` | `system.workflow.${string}.failed` | `system.activity.${string}.${string}.started` | `system.activity.${string}.${string}.completed` | `system.activity.${string}.${string}.failed` | `system.knowledge.${string}.stored` | `system.knowledge.${string}.deleted` | 'system.file.stored' | 'system.file.deleted' | `system.agent.${string}.started` | `system.agent.${string}.completed` | `system.agent.${string}.failed` | `system.agent.${string}.status_changed` | `system.agent.${string}.triggers_changed` | `system.milestone.${string}`;
|
|
17
22
|
/** @deprecated Use LTSystemEventPattern for system events. Kept for backward compat. */
|
|
18
23
|
export type LTEventType = LTSystemEventPattern;
|
|
19
24
|
/**
|
|
@@ -63,6 +68,8 @@ export interface LTEvent extends LTEventBase {
|
|
|
63
68
|
taskId?: string;
|
|
64
69
|
/** Escalation ID — present on escalation events. */
|
|
65
70
|
escalationId?: string;
|
|
71
|
+
/** Escalation role (the queue) — present on escalation events. */
|
|
72
|
+
role?: string;
|
|
66
73
|
/** Root process lineage — present on workflow/task/escalation events. */
|
|
67
74
|
originId?: string;
|
|
68
75
|
/** Lifecycle status. Vocabulary is per-family (see the family interfaces). */
|
|
@@ -91,9 +98,10 @@ export interface LTTaskEvent extends LTEventBase, LTWorkflowContext {
|
|
|
91
98
|
status: string;
|
|
92
99
|
milestones?: LTMilestone[];
|
|
93
100
|
}
|
|
94
|
-
/** `system.escalation.{escalationId}.{created|resolved|claimed|released}`. status ∈ pending|claimed|released|resolved|cancelled. */
|
|
101
|
+
/** `system.escalation.{role}.{escalationId}.{created|resolved|claimed|released|cancelled|reassigned|expired}`. status ∈ pending|claimed|released|resolved|cancelled|expired. */
|
|
95
102
|
export interface LTEscalationEvent extends LTEventBase, LTWorkflowContext {
|
|
96
103
|
escalationId: string;
|
|
104
|
+
role: string;
|
|
97
105
|
status: string;
|
|
98
106
|
}
|
|
99
107
|
/** `system.activity.{workflowId}.{activityName}.{started|completed|failed}`. */
|