@hotmeshio/long-tail 0.7.4 → 0.8.0
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/roles.d.ts +4 -0
- package/build/api/roles.js +7 -1
- package/build/api/workflows/config.d.ts +7 -1
- package/build/api/workflows/config.js +7 -1
- package/build/api/workflows/discovery.js +1 -4
- package/build/lib/db/schemas/019_role_priority.sql +28 -0
- package/build/lib/db/schemas/020_workflow_certified.sql +34 -0
- package/build/modules/ltconfig.d.ts +3 -2
- package/build/modules/ltconfig.js +4 -4
- package/build/routes/roles.js +1 -1
- package/build/routes/workflows/config.js +1 -0
- package/build/scripts/ortho-populate.d.ts +7 -1
- package/build/scripts/ortho-populate.js +21 -6
- package/build/services/config/cache.js +1 -0
- package/build/services/config/read.js +2 -0
- package/build/services/config/sql.d.ts +2 -2
- package/build/services/config/sql.js +6 -5
- package/build/services/config/write.js +13 -0
- package/build/services/escalation/bulk.d.ts +3 -1
- package/build/services/escalation/bulk.js +3 -1
- package/build/services/escalation/crud.d.ts +4 -3
- package/build/services/escalation/crud.js +4 -3
- package/build/services/escalation/facet-sql.d.ts +1 -0
- package/build/services/escalation/facet-sql.js +7 -6
- package/build/services/escalation/queries.js +27 -5
- package/build/services/escalation/sql.d.ts +19 -2
- package/build/services/escalation/sql.js +32 -9
- package/build/services/escalation/types.d.ts +7 -1
- package/build/services/role/index.js +2 -0
- package/build/services/role/sql.d.ts +4 -4
- package/build/services/role/sql.js +12 -6
- package/build/services/role/types.d.ts +14 -0
- package/build/start/workers.js +1 -0
- package/build/system/mcp-servers/admin/schemas.d.ts +9 -0
- package/build/system/mcp-servers/admin/schemas.js +6 -1
- package/build/system/mcp-servers/admin/users.js +4 -1
- package/build/system/mcp-servers/admin/workflow-config.js +1 -0
- package/build/system/seed/tool-manifests-admin.d.ts +152 -0
- package/build/system/seed/tool-manifests-admin.js +1 -1
- package/build/types/config.d.ts +16 -0
- package/build/types/startup.d.ts +11 -1
- package/dashboard/dist/assets/{AdminDashboard-C9eE1VEp.js → AdminDashboard-9JLg41f-.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-C9eE1VEp.js.map → AdminDashboard-9JLg41f-.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-Ba8QfXM2.js → AgentConfigPage-D5P1hcOc.js} +6 -6
- package/dashboard/dist/assets/{AgentConfigPage-Ba8QfXM2.js.map → AgentConfigPage-D5P1hcOc.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-DVmec0CP.js → AgentDetailPage-DrijeAV8.js} +4 -4
- package/dashboard/dist/assets/{AgentDetailPage-DVmec0CP.js.map → AgentDetailPage-DrijeAV8.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-DNiCYMh3.js → AgentsPage-BW5d0JOt.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-DNiCYMh3.js.map → AgentsPage-BW5d0JOt.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-gDIF8ocC.js → AvailableEscalationsPage-CoZ4Lufr.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-gDIF8ocC.js.map → AvailableEscalationsPage-CoZ4Lufr.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-3wBcBavT.js → BotPicker-xGUCxJo-.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-3wBcBavT.js.map → BotPicker-xGUCxJo-.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-WoPkND2y.js → CapabilitiesPage-ChaRJiyg.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-WoPkND2y.js.map → CapabilitiesPage-ChaRJiyg.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-Cx99mqNN.js → CollapsibleSection-CXMPecjj.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-Cx99mqNN.js.map → CollapsibleSection-CXMPecjj.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-DbNaoPbF.js → CredentialsPage-BbdfZh1D.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-DbNaoPbF.js.map → CredentialsPage-BbdfZh1D.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-DLW4_Zg4.js → CronLabel-CJUL50eO.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-DLW4_Zg4.js.map → CronLabel-CJUL50eO.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-BRUFjkiu.js → CustomDurationPicker-id6Tq64R.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-BRUFjkiu.js.map → CustomDurationPicker-id6Tq64R.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-DEX0BBqt.js → DropZone-CZDmNBn-.js} +2 -2
- package/dashboard/dist/assets/{DropZone-DEX0BBqt.js.map → DropZone-CZDmNBn-.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-BtmDQaym.js → ElapsedCell-B8TrnyT5.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-BtmDQaym.js.map → ElapsedCell-B8TrnyT5.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-Bm4yBEGN.js → EscalationSchemaPage-C6UuZgCD.js} +2 -2
- package/dashboard/dist/assets/{EscalationSchemaPage-Bm4yBEGN.js.map → EscalationSchemaPage-C6UuZgCD.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-B3xZwTQA.js → EscalationsOverview-CjLyujJ3.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-B3xZwTQA.js.map → EscalationsOverview-CjLyujJ3.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-Bh9FKXLI.js → EventTable-D_rNmyGG.js} +2 -2
- package/dashboard/dist/assets/{EventTable-Bh9FKXLI.js.map → EventTable-D_rNmyGG.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-ov_ANlaE.js → GraphInvokePage-BMyrTnI6.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-ov_ANlaE.js.map → GraphInvokePage-BMyrTnI6.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-D0DV6izb.js → HomePage-MBv6pwk4.js} +2 -2
- package/dashboard/dist/assets/{HomePage-D0DV6izb.js.map → HomePage-MBv6pwk4.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-FpcvqNkN.js → ListToolbar--FkPpYDY.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-FpcvqNkN.js.map → ListToolbar--FkPpYDY.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-DcuRiAff.js → McpOverview-CtAFXv-T.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-DcuRiAff.js.map → McpOverview-CtAFXv-T.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-BcYl67KP.js → McpQueryDetailPage-5Jzz2q2g.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-BcYl67KP.js.map → McpQueryDetailPage-5Jzz2q2g.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-C3GDzqZM.js → McpQueryPage-DveeRF5I.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-C3GDzqZM.js.map → McpQueryPage-DveeRF5I.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-SzOyhDBW.js → McpRunDetailPage-BYIxBcA7.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-SzOyhDBW.js.map → McpRunDetailPage-BYIxBcA7.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-BwgB6mRV.js → McpRunsPage-Cgke6ask.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-BwgB6mRV.js.map → McpRunsPage-Cgke6ask.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-CwKdoyRM.js → NamespacePill-DlqBTvFR.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-CwKdoyRM.js.map → NamespacePill-DlqBTvFR.js.map} +1 -1
- package/dashboard/dist/assets/OperationsPage-D2i7xrAI.js +2 -0
- package/dashboard/dist/assets/OperationsPage-D2i7xrAI.js.map +1 -0
- package/dashboard/dist/assets/{OperatorDashboard-DSXh-yYw.js → OperatorDashboard-DMQwodfo.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-DSXh-yYw.js.map → OperatorDashboard-DMQwodfo.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-BhaWTWcM.js → PageHeader-CFta2VaS.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-BhaWTWcM.js.map → PageHeader-CFta2VaS.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-yex5WmHB.js → PageHeaderWithStats-CcVAji-7.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-yex5WmHB.js.map → PageHeaderWithStats-CcVAji-7.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-iIB1rwEt.js → ProcessDetailPage-Dodrk5-z.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-iIB1rwEt.js.map → ProcessDetailPage-Dodrk5-z.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-BrqWR2zr.js → ProcessesListPage-BVtkWVLY.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-BrqWR2zr.js.map → ProcessesListPage-BVtkWVLY.js.map} +1 -1
- package/dashboard/dist/assets/RoleDetailPage-8NldZI49.js +11 -0
- package/dashboard/dist/assets/RoleDetailPage-8NldZI49.js.map +1 -0
- package/dashboard/dist/assets/{RolePill-Cl71eDUA.js → RolePill-CXEyPMqb.js} +2 -2
- package/dashboard/dist/assets/{RolePill-Cl71eDUA.js.map → RolePill-CXEyPMqb.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-Bzp9FhAl.js → RolesPage-BJBjtFNY.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-Bzp9FhAl.js.map → RolesPage-BJBjtFNY.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-DXbHRxQs.js → RunAsSelector-Cc1i017Z.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-DXbHRxQs.js.map → RunAsSelector-Cc1i017Z.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-D8XuMSWD.js → StickyPagination-GQKFFTjL.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-D8XuMSWD.js.map → StickyPagination-GQKFFTjL.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-D5v95pmz.js → StreamMessageDetail-BYzfjWe_.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-D5v95pmz.js.map → StreamMessageDetail-BYzfjWe_.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-CUEf2R5R.js → SwimlaneTimeline-DLVmRrd-.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-CUEf2R5R.js.map → SwimlaneTimeline-DLVmRrd-.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-B_WQiuer.js → TagInput-CQg-TrV9.js} +2 -2
- package/dashboard/dist/assets/{TagInput-B_WQiuer.js.map → TagInput-CQg-TrV9.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-BJvKNwEe.js → TaskDetailPage-HzQpzp6D.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-BJvKNwEe.js.map → TaskDetailPage-HzQpzp6D.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-Lgn2obNU.js → TaskQueuePill-DyvtL8X4.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-Lgn2obNU.js.map → TaskQueuePill-DyvtL8X4.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-CM7BWh_h.js → TasksListPage-DpqevgTz.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-CM7BWh_h.js.map → TasksListPage-DpqevgTz.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-D1K7xKq5.js → TimeAgo-CftB8aJE.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-D1K7xKq5.js.map → TimeAgo-CftB8aJE.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-7G0echgP.js → TimestampCell-BSKj1jqT.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-7G0echgP.js.map → TimestampCell-BSKj1jqT.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-uVqcbHPE.js → ToolPill-miuRcj1Q.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-uVqcbHPE.js.map → ToolPill-miuRcj1Q.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-LxuJvURK.js → ToolTestPanel-DVQICZUQ.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-LxuJvURK.js.map → ToolTestPanel-DVQICZUQ.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-JvAX6rrR.js → TopicDetailPage-B2LAQDEg.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-JvAX6rrR.js.map → TopicDetailPage-B2LAQDEg.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-tFT2AcTz.js → TopicsPage-SwPAnN2C.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-tFT2AcTz.js.map → TopicsPage-SwPAnN2C.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-Djz0nmaZ.js → UserName-Ce9gvlT5.js} +2 -2
- package/dashboard/dist/assets/{UserName-Djz0nmaZ.js.map → UserName-Ce9gvlT5.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-f53hilbI.js → WorkflowExecutionPage-BI9NzeaH.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-f53hilbI.js.map → WorkflowExecutionPage-BI9NzeaH.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-IDjTRfQ8.js → WorkflowPill-BuNkWUVM.js} +2 -2
- package/dashboard/dist/assets/WorkflowPill-BuNkWUVM.js.map +1 -0
- package/dashboard/dist/assets/{WorkflowsDashboard-DM9Xe665.js → WorkflowsDashboard-CvWSgQdE.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-DM9Xe665.js.map → WorkflowsDashboard-CvWSgQdE.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-CUGSrx9N.js → WorkflowsOverview-CjBWlwlH.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-CUGSrx9N.js.map → WorkflowsOverview-CjBWlwlH.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-B1_yqxAw.js → YamlWorkflowDetailPage-Ds5o1UK9.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-B1_yqxAw.js.map → YamlWorkflowDetailPage-Ds5o1UK9.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-NtGvqiu7.js → YamlWorkflowsPage-ChwvZS4Z.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-NtGvqiu7.js.map → YamlWorkflowsPage-ChwvZS4Z.js.map} +1 -1
- package/dashboard/dist/assets/{agents-tML6AjDj.js → agents-A1U43853.js} +2 -2
- package/dashboard/dist/assets/{agents-tML6AjDj.js.map → agents-A1U43853.js.map} +1 -1
- package/dashboard/dist/assets/{bots-Cb0WTwhY.js → bots-CyzN6Uxi.js} +2 -2
- package/dashboard/dist/assets/{bots-Cb0WTwhY.js.map → bots-CyzN6Uxi.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-BGZogsi_.js → capabilities-BE1X5FVI.js} +2 -2
- package/dashboard/dist/assets/{capabilities-BGZogsi_.js.map → capabilities-BE1X5FVI.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-B7VJTlZD.js → controlplane-BrwK_MT8.js} +2 -2
- package/dashboard/dist/assets/{controlplane-B7VJTlZD.js.map → controlplane-BrwK_MT8.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-Bl-SQV_u.js → escalation-DDdt7UdU.js} +2 -2
- package/dashboard/dist/assets/{escalation-Bl-SQV_u.js.map → escalation-DDdt7UdU.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-BlJOswRx.js → escalation-columns-D_zFY1zF.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-BlJOswRx.js.map → escalation-columns-D_zFY1zF.js.map} +1 -1
- package/dashboard/dist/assets/{index-DcbEIXit.js → index-6MALVAEY.js} +2 -2
- package/dashboard/dist/assets/{index-DcbEIXit.js.map → index-6MALVAEY.js.map} +1 -1
- package/dashboard/dist/assets/{index-CBv3UxF2.js → index-BNWKksZ6.js} +2 -2
- package/dashboard/dist/assets/{index-CBv3UxF2.js.map → index-BNWKksZ6.js.map} +1 -1
- package/dashboard/dist/assets/{index-DfDfJivY.js → index-BtrNxebh.js} +2 -2
- package/dashboard/dist/assets/{index-DfDfJivY.js.map → index-BtrNxebh.js.map} +1 -1
- package/dashboard/dist/assets/{index-BorpZbZA.js → index-C-rJQ-vB.js} +2 -2
- package/dashboard/dist/assets/{index-BorpZbZA.js.map → index-C-rJQ-vB.js.map} +1 -1
- package/dashboard/dist/assets/{index-Il_g7kw5.js → index-CGUBekEU.js} +2 -2
- package/dashboard/dist/assets/{index-Il_g7kw5.js.map → index-CGUBekEU.js.map} +1 -1
- package/dashboard/dist/assets/{index-Dgw1KKpq.js → index-CKXSKsVZ.js} +4 -4
- package/dashboard/dist/assets/{index-Dgw1KKpq.js.map → index-CKXSKsVZ.js.map} +1 -1
- package/dashboard/dist/assets/{index-Wny0bRgq.css → index-CZ6-l8_0.css} +1 -1
- package/dashboard/dist/assets/{index--WeZDfeN.js → index-D2dDPGNk.js} +2 -2
- package/dashboard/dist/assets/{index--WeZDfeN.js.map → index-D2dDPGNk.js.map} +1 -1
- package/dashboard/dist/assets/{index-0o71lRuY.js → index-D4U--3Xo.js} +2 -2
- package/dashboard/dist/assets/{index-0o71lRuY.js.map → index-D4U--3Xo.js.map} +1 -1
- package/dashboard/dist/assets/{index-e97M6GoI.js → index-D4gAsCGh.js} +2 -2
- package/dashboard/dist/assets/{index-e97M6GoI.js.map → index-D4gAsCGh.js.map} +1 -1
- package/dashboard/dist/assets/{index-SCrD3l-K.js → index-DEXouwBQ.js} +2 -2
- package/dashboard/dist/assets/{index-SCrD3l-K.js.map → index-DEXouwBQ.js.map} +1 -1
- package/dashboard/dist/assets/{index-3A_5CL81.js → index-NnGsWGNS.js} +2 -2
- package/dashboard/dist/assets/{index-3A_5CL81.js.map → index-NnGsWGNS.js.map} +1 -1
- package/dashboard/dist/assets/index-U27KBbTV.js +9 -0
- package/dashboard/dist/assets/index-U27KBbTV.js.map +1 -0
- package/dashboard/dist/assets/index-fwHQSJCp.js +6 -0
- package/dashboard/dist/assets/index-fwHQSJCp.js.map +1 -0
- package/dashboard/dist/assets/{knowledge-CDzw4E6q.js → knowledge-B3ZIRTeu.js} +2 -2
- package/dashboard/dist/assets/{knowledge-CDzw4E6q.js.map → knowledge-B3ZIRTeu.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-D_-NQtnG.js → mcp-BJjWiHdc.js} +2 -2
- package/dashboard/dist/assets/{mcp-D_-NQtnG.js.map → mcp-BJjWiHdc.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-BqZXdf9A.js → mcp-query-ksjBztwq.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-BqZXdf9A.js.map → mcp-query-ksjBztwq.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-CNLhgj8b.js → pipelines-DT1astmP.js} +2 -2
- package/dashboard/dist/assets/{pipelines-CNLhgj8b.js.map → pipelines-DT1astmP.js.map} +1 -1
- package/dashboard/dist/assets/{roles-CFD2eYap.js → roles-UboiQxXT.js} +2 -2
- package/dashboard/dist/assets/roles-UboiQxXT.js.map +1 -0
- package/dashboard/dist/assets/{tasks-DcSvF636.js → tasks-aL0K8WW3.js} +2 -2
- package/dashboard/dist/assets/{tasks-DcSvF636.js.map → tasks-aL0K8WW3.js.map} +1 -1
- package/dashboard/dist/assets/{topics-DI8TFSZv.js → topics-CZO06VJl.js} +2 -2
- package/dashboard/dist/assets/{topics-DI8TFSZv.js.map → topics-CZO06VJl.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-DcIgMDh3.js → useEventHooks-DlWkui_n.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-DcIgMDh3.js.map → useEventHooks-DlWkui_n.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-C88ZxGoX.js → useNamespace-BBzCmCIN.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-C88ZxGoX.js.map → useNamespace-BBzCmCIN.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-D2-yVjJ7.js → useYamlActivityEvents-ZS6wRSSc.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-D2-yVjJ7.js.map → useYamlActivityEvents-ZS6wRSSc.js.map} +1 -1
- package/dashboard/dist/assets/{users-C0WV36X8.js → users-Dzh04pRB.js} +2 -2
- package/dashboard/dist/assets/{users-C0WV36X8.js.map → users-Dzh04pRB.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-CEWCGPeJ.js → vendor-icons-BaQqUm-e.js} +2 -2
- package/dashboard/dist/assets/{vendor-icons-CEWCGPeJ.js.map → vendor-icons-BaQqUm-e.js.map} +1 -1
- package/dashboard/dist/assets/{workflows-CkPv7xk-.js → workflows-BTkHs6VT.js} +2 -2
- package/dashboard/dist/assets/workflows-BTkHs6VT.js.map +1 -0
- package/dashboard/dist/assets/{yaml-workflows-BjrMQLTK.js → yaml-workflows-Df8u3lgx.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-BjrMQLTK.js.map → yaml-workflows-Df8u3lgx.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/api/http/escalations.md +6 -6
- package/docs/api/http/roles.md +6 -0
- package/docs/api/http/workflows.md +2 -1
- package/docs/api/mcp/admin.md +15 -7
- package/docs/api/sdk/escalations.md +5 -3
- package/docs/api/sdk/roles.md +7 -1
- package/docs/api/sdk/workflows.md +3 -2
- package/docs/architecture.md +2 -2
- package/docs/dashboard.md +11 -9
- package/docs/data.md +2 -0
- package/docs/iam.md +3 -3
- package/docs/operations.md +16 -3
- package/docs/workflows.md +7 -5
- package/package.json +2 -2
- package/dashboard/dist/assets/OperationsPage-BCr21p8I.js +0 -2
- package/dashboard/dist/assets/OperationsPage-BCr21p8I.js.map +0 -1
- package/dashboard/dist/assets/RoleDetailPage-DS37tJhq.js +0 -11
- package/dashboard/dist/assets/RoleDetailPage-DS37tJhq.js.map +0 -1
- package/dashboard/dist/assets/WorkflowPill-IDjTRfQ8.js.map +0 -1
- package/dashboard/dist/assets/index-D0-8byNu.js +0 -6
- package/dashboard/dist/assets/index-D0-8byNu.js.map +0 -1
- package/dashboard/dist/assets/index-TiKh2Ctj.js +0 -9
- package/dashboard/dist/assets/index-TiKh2Ctj.js.map +0 -1
- package/dashboard/dist/assets/roles-CFD2eYap.js.map +0 -1
- package/dashboard/dist/assets/workflows-CkPv7xk-.js.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{u as n,b as t,c as u}from"./vendor-query-B2UbickB.js";import{d as s}from"./index-
|
|
2
|
-
//# sourceMappingURL=workflows-
|
|
1
|
+
import{u as n,b as t,c as u}from"./vendor-query-B2UbickB.js";import{d as s}from"./index-CKXSKsVZ.js";function f(){return n({queryKey:["activeWorkers"],queryFn:async()=>(await s("/workflows/workers")).workers})}function w(){return n({queryKey:["discoveredWorkflows"],queryFn:async()=>(await s("/workflows/discovered")).workflows})}function l(){return n({queryKey:["workflowConfigs"],queryFn:async()=>(await s("/workflows/config")).workflows})}function d(){return n({queryKey:["cronStatus"],queryFn:async()=>(await s("/workflows/cron/status")).schedules})}function k(e){return n({queryKey:["workflowExecution",e],queryFn:()=>s(`/workflow-states/${e}/execution`),enabled:!!e})}function m(e,o){const r=new URLSearchParams;return e.limit&&r.set("limit",String(e.limit)),e.offset!==void 0&&r.set("offset",String(e.offset)),e.entity&&r.set("entity",e.entity),e.search&&r.set("search",e.search),e.status&&r.set("status",e.status),e.sort_by&&r.set("sort_by",e.sort_by),e.order&&r.set("order",e.order),e.registered&&r.set("registered",e.registered),e.namespace&&r.set("namespace",e.namespace),n({queryKey:["jobs",e],queryFn:()=>s(`/workflow-states/jobs?${r}`),enabled:(o==null?void 0:o.enabled)??!0})}function q(){const e=t();return u({mutationFn:o=>s(`/workflows/${o}/terminate`,{method:"POST"}),onSuccess:(o,r)=>{e.invalidateQueries({queryKey:["workflowExecution",r],refetchType:"all"}),e.invalidateQueries({queryKey:["jobs"],refetchType:"all"})}})}function g(){const e=t();return u({mutationFn:({workflow_type:o,...r})=>s(`/workflows/${encodeURIComponent(o)}/config`,{method:"PUT",body:JSON.stringify(r)}),onSuccess:()=>{e.invalidateQueries({queryKey:["workflowConfigs"],refetchType:"all"})}})}function h(){const e=t();return u({mutationFn:o=>s(`/workflows/${encodeURIComponent(o)}/config`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:["workflowConfigs"],refetchType:"all"})}})}function b(){const e=t();return u({mutationFn:({workflowType:o,data:r,metadata:i,execute_as:a})=>s(`/workflows/${o}/invoke`,{method:"POST",body:JSON.stringify({data:r,metadata:i,...a?{execute_as:a}:{}})}),onSuccess:()=>{e.invalidateQueries({queryKey:["tasks"],refetchType:"all"}),e.invalidateQueries({queryKey:["jobs"],refetchType:"all"})}})}export{k as a,m as b,b as c,w as d,d as e,q as f,f as g,h,g as i,l as u};
|
|
2
|
+
//# sourceMappingURL=workflows-BTkHs6VT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflows-BTkHs6VT.js","sources":["../../src/api/workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { ActiveWorker, CronScheduleEntry, DiscoveredWorkflow, LTJob, LTWorkflowConfig, WorkflowExecution } from './types';\n\nexport function useActiveWorkers() {\n return useQuery<ActiveWorker[]>({\n queryKey: ['activeWorkers'],\n queryFn: async () => {\n const res = await apiFetch<{ workers: ActiveWorker[] }>('/workflows/workers');\n return res.workers;\n },\n });\n}\n\nexport function useDiscoveredWorkflows() {\n return useQuery<DiscoveredWorkflow[]>({\n queryKey: ['discoveredWorkflows'],\n queryFn: async () => {\n const res = await apiFetch<{ workflows: DiscoveredWorkflow[] }>('/workflows/discovered');\n return res.workflows;\n },\n });\n}\n\nexport function useWorkflowConfigs() {\n return useQuery<LTWorkflowConfig[]>({\n queryKey: ['workflowConfigs'],\n queryFn: async () => {\n const res = await apiFetch<{ workflows: LTWorkflowConfig[] }>('/workflows/config');\n return res.workflows;\n },\n });\n}\n\nexport function useCronStatus() {\n return useQuery<CronScheduleEntry[]>({\n queryKey: ['cronStatus'],\n queryFn: async () => {\n const res = await apiFetch<{ schedules: CronScheduleEntry[] }>('/workflows/cron/status');\n return res.schedules;\n },\n });\n}\n\nexport function useWorkflowExecution(workflowId: string) {\n return useQuery<WorkflowExecution>({\n queryKey: ['workflowExecution', workflowId],\n queryFn: () =>\n apiFetch(`/workflow-states/${workflowId}/execution`),\n enabled: !!workflowId,\n });\n}\n\nexport function useWorkflowState(workflowId: string) {\n return useQuery<{ workflow_id: string; state: Record<string, unknown> }>({\n queryKey: ['workflowState', workflowId],\n queryFn: () => apiFetch(`/workflow-states/${workflowId}/state`),\n enabled: !!workflowId,\n });\n}\n\nexport function useJobs(filters: {\n limit?: number;\n offset?: number;\n entity?: string;\n search?: string;\n status?: string;\n sort_by?: string;\n order?: string;\n registered?: string;\n namespace?: string;\n}, options?: { enabled?: boolean }) {\n const params = new URLSearchParams();\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n if (filters.entity) params.set('entity', filters.entity);\n if (filters.search) params.set('search', filters.search);\n if (filters.status) params.set('status', filters.status);\n if (filters.sort_by) params.set('sort_by', filters.sort_by);\n if (filters.order) params.set('order', filters.order);\n if (filters.registered) params.set('registered', filters.registered);\n if (filters.namespace) params.set('namespace', filters.namespace);\n\n return useQuery<{ jobs: LTJob[]; total: number }>({\n queryKey: ['jobs', filters],\n queryFn: () => apiFetch(`/workflow-states/jobs?${params}`),\n enabled: options?.enabled ?? true,\n });\n}\n\nexport function useTerminateWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (workflowId: string) =>\n apiFetch(`/workflows/${workflowId}/terminate`, { method: 'POST' }),\n onSuccess: (_data, workflowId) => {\n queryClient.invalidateQueries({ queryKey: ['workflowExecution', workflowId], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['jobs'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpsertWorkflowConfig() {\n const queryClient = useQueryClient();\n return useMutation<\n LTWorkflowConfig,\n Error,\n {\n workflow_type: string;\n description?: string | null;\n\n invocable?: boolean;\n certified?: boolean;\n task_queue?: string | null;\n default_role?: string;\n roles?: string[];\n invocation_roles?: string[];\n consumes?: string[];\n envelope_schema?: Record<string, unknown> | null;\n resolver_schema?: Record<string, unknown> | null;\n cron_schedule?: string | null;\n execute_as?: string | null;\n }\n >({\n mutationFn: ({ workflow_type, ...body }) =>\n apiFetch(`/workflows/${encodeURIComponent(workflow_type)}/config`, {\n method: 'PUT',\n body: JSON.stringify(body),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['workflowConfigs'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteWorkflowConfig() {\n const queryClient = useQueryClient();\n return useMutation<{ deleted: boolean; workflow_type: string }, Error, string>({\n mutationFn: (workflowType) =>\n apiFetch(`/workflows/${encodeURIComponent(workflowType)}/config`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['workflowConfigs'], refetchType: 'all' });\n },\n });\n}\n\nexport function useSetCronSchedule() {\n const queryClient = useQueryClient();\n return useMutation<\n LTWorkflowConfig,\n Error,\n { config: LTWorkflowConfig; cron_schedule: string | null; envelope_schema?: Record<string, unknown> | null }\n >({\n mutationFn: ({ config, cron_schedule, envelope_schema }) =>\n apiFetch(`/workflows/${encodeURIComponent(config.workflow_type)}/config`, {\n method: 'PUT',\n body: JSON.stringify({\n ...config,\n cron_schedule,\n ...(envelope_schema !== undefined ? { envelope_schema } : {}),\n }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['workflowConfigs'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['cronStatus'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeWorkflow() {\n const queryClient = useQueryClient();\n return useMutation<\n { workflowId: string; message: string },\n Error,\n { workflowType: string; data: Record<string, unknown>; metadata?: Record<string, unknown>; execute_as?: string }\n >({\n mutationFn: ({ workflowType, data, metadata, execute_as }) =>\n apiFetch(`/workflows/${workflowType}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, metadata, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['tasks'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['jobs'], refetchType: 'all' });\n },\n });\n}\n"],"names":["useActiveWorkers","useQuery","apiFetch","useDiscoveredWorkflows","useWorkflowConfigs","useCronStatus","useWorkflowExecution","workflowId","useJobs","filters","options","params","useTerminateWorkflow","queryClient","useQueryClient","useMutation","_data","useUpsertWorkflowConfig","workflow_type","body","useDeleteWorkflowConfig","workflowType","useInvokeWorkflow","data","metadata","execute_as"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{u as l,b as a,c as s}from"./vendor-query-B2UbickB.js";import{d as r}from"./index-
|
|
2
|
-
//# sourceMappingURL=yaml-workflows-
|
|
1
|
+
import{u as l,b as a,c as s}from"./vendor-query-B2UbickB.js";import{d as r}from"./index-CKXSKsVZ.js";function f(e={}){const o=new URLSearchParams;return e.status&&o.set("status",e.status),e.graph_topic&&o.set("graph_topic",e.graph_topic),e.app_id&&o.set("app_id",e.app_id),e.search&&o.set("search",e.search),e.set_id&&o.set("set_id",e.set_id),e.limit&&o.set("limit",String(e.limit)),e.offset!==void 0&&o.set("offset",String(e.offset)),l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows?${o}`)})}function m(){return l({queryKey:["yamlWorkflowAppIds"],queryFn:()=>r("/yaml-workflows/app-ids")})}function c(e){return l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows/${e}`),enabled:!!e})}function w(){const e=a();return s({mutationFn:o=>r("/yaml-workflows",{method:"POST",body:JSON.stringify(o)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function k(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/deploy`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function p(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/activate`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function d(){const e=a();return s({mutationFn:({id:o,data:t,sync:n,execute_as:u})=>r(`/yaml-workflows/${o}/invoke`,{method:"POST",body:JSON.stringify({data:t,sync:n,...u?{execute_as:u}:{}})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function h(){const e=a();return s({mutationFn:({id:o,task_queue:t,compilation_feedback:n})=>r(`/yaml-workflows/${o}/regenerate`,{method:"POST",body:JSON.stringify({task_queue:t,compilation_feedback:n})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function q(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/archive`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function W(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/restore`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"}),e.invalidateQueries({queryKey:["yamlWorkflow"],refetchType:"all"})}})}function S(){const e=a();return s({mutationFn:({id:o,...t})=>r(`/yaml-workflows/${o}`,{method:"PUT",body:JSON.stringify(t)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function v(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function T(e){return l({queryKey:["yamlWorkflows",e,"versions"],queryFn:()=>r(`/yaml-workflows/${e}/versions`),enabled:!!e})}function F(e,o){return l({queryKey:["yamlWorkflows",e,"versions",o],queryFn:()=>r(`/yaml-workflows/${e}/versions/${o}`),enabled:!!e&&o!==null})}export{m as a,S as b,c,T as d,k as e,p as f,q as g,W as h,v as i,h as j,F as k,d as l,w as m,f as u};
|
|
2
|
+
//# sourceMappingURL=yaml-workflows-Df8u3lgx.js.map
|
package/dashboard/dist/assets/{yaml-workflows-BjrMQLTK.js.map → yaml-workflows-Df8u3lgx.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml-workflows-BjrMQLTK.js","sources":["../../src/api/yaml-workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { LTYamlWorkflowRecord, LTYamlWorkflowStatus, LTYamlWorkflowVersion } from './types';\n\ninterface YamlWorkflowListResponse {\n workflows: LTYamlWorkflowRecord[];\n total: number;\n}\n\ninterface YamlWorkflowFilters {\n status?: LTYamlWorkflowStatus;\n graph_topic?: string;\n app_id?: string;\n search?: string;\n set_id?: string;\n limit?: number;\n offset?: number;\n}\n\nexport function useYamlWorkflows(filters: YamlWorkflowFilters = {}) {\n const params = new URLSearchParams();\n if (filters.status) params.set('status', filters.status);\n if (filters.graph_topic) params.set('graph_topic', filters.graph_topic);\n if (filters.app_id) params.set('app_id', filters.app_id);\n if (filters.search) params.set('search', filters.search);\n if (filters.set_id) params.set('set_id', filters.set_id);\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', filters],\n queryFn: () => apiFetch(`/yaml-workflows?${params}`),\n });\n}\n\nexport function useYamlWorkflowAppIds() {\n return useQuery<{ app_ids: string[] }>({\n queryKey: ['yamlWorkflowAppIds'],\n queryFn: () => apiFetch('/yaml-workflows/app-ids'),\n });\n}\n\nexport function useYamlWorkflowByTopic(graphTopic: string | undefined, appId?: string) {\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', 'byTopic', graphTopic, appId],\n queryFn: () => {\n const params = new URLSearchParams({ graph_topic: graphTopic!, limit: '1' });\n if (appId) params.set('app_id', appId);\n return apiFetch(`/yaml-workflows?${params}`);\n },\n enabled: !!graphTopic,\n });\n}\n\nexport function useYamlWorkflow(id: string) {\n return useQuery<LTYamlWorkflowRecord>({\n queryKey: ['yamlWorkflows', id],\n queryFn: () => apiFetch(`/yaml-workflows/${id}`),\n enabled: !!id,\n });\n}\n\nexport function useCreateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (input: {\n workflow_id: string;\n task_queue: string;\n workflow_name: string;\n name: string;\n description?: string;\n app_id?: string;\n subscribes?: string;\n tags?: string[];\n compilation_feedback?: string;\n }) =>\n apiFetch<LTYamlWorkflowRecord>('/yaml-workflows', {\n method: 'POST',\n body: JSON.stringify(input),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeployYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/deploy`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useActivateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/activate`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, data, sync, execute_as }: { id: string; data: Record<string, unknown>; sync?: boolean; execute_as?: string }) =>\n apiFetch<{ result?: unknown; job_id?: string }>(`/yaml-workflows/${id}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, sync, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRegenerateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, task_queue, compilation_feedback }: { id: string; task_queue?: string; compilation_feedback?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/regenerate`, {\n method: 'POST',\n body: JSON.stringify({ task_queue, compilation_feedback }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useArchiveYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/archive`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRestoreYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/restore`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflow'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpdateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, ...updates }: { id: string; yaml_content?: string; name?: string; description?: string; input_schema?: Record<string, unknown>; output_schema?: Record<string, unknown>; tags?: string[]; app_id?: string; graph_topic?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}`, {\n method: 'PUT',\n body: JSON.stringify(updates),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<{ deleted: boolean }>(`/yaml-workflows/${id}`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Cron scheduling ─────────────────────────────────────────────\n\nexport function useSetYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, cron_schedule, cron_envelope, execute_as }: {\n id: string;\n cron_schedule: string;\n cron_envelope?: Record<string, unknown> | null;\n execute_as?: string | null;\n }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'PUT',\n body: JSON.stringify({ cron_schedule, cron_envelope, execute_as }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useClearYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Version history ─────────────────────────────────────────────\n\nexport function useYamlWorkflowVersions(id: string) {\n return useQuery<{ versions: LTYamlWorkflowVersion[]; total: number }>({\n queryKey: ['yamlWorkflows', id, 'versions'],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions`),\n enabled: !!id,\n });\n}\n\nexport function useYamlWorkflowVersion(id: string, version: number | null) {\n return useQuery<LTYamlWorkflowVersion>({\n queryKey: ['yamlWorkflows', id, 'versions', version],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions/${version}`),\n enabled: !!id && version !== null,\n });\n}\n"],"names":["useYamlWorkflows","filters","params","useQuery","apiFetch","useYamlWorkflowAppIds","useYamlWorkflow","id","useCreateYamlWorkflow","queryClient","useQueryClient","useMutation","input","useDeployYamlWorkflow","useActivateYamlWorkflow","useInvokeYamlWorkflow","data","sync","execute_as","useRegenerateYamlWorkflow","task_queue","compilation_feedback","useArchiveYamlWorkflow","useRestoreYamlWorkflow","useUpdateYamlWorkflow","updates","useDeleteYamlWorkflow","useYamlWorkflowVersions","useYamlWorkflowVersion","version"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"yaml-workflows-Df8u3lgx.js","sources":["../../src/api/yaml-workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { LTYamlWorkflowRecord, LTYamlWorkflowStatus, LTYamlWorkflowVersion } from './types';\n\ninterface YamlWorkflowListResponse {\n workflows: LTYamlWorkflowRecord[];\n total: number;\n}\n\ninterface YamlWorkflowFilters {\n status?: LTYamlWorkflowStatus;\n graph_topic?: string;\n app_id?: string;\n search?: string;\n set_id?: string;\n limit?: number;\n offset?: number;\n}\n\nexport function useYamlWorkflows(filters: YamlWorkflowFilters = {}) {\n const params = new URLSearchParams();\n if (filters.status) params.set('status', filters.status);\n if (filters.graph_topic) params.set('graph_topic', filters.graph_topic);\n if (filters.app_id) params.set('app_id', filters.app_id);\n if (filters.search) params.set('search', filters.search);\n if (filters.set_id) params.set('set_id', filters.set_id);\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', filters],\n queryFn: () => apiFetch(`/yaml-workflows?${params}`),\n });\n}\n\nexport function useYamlWorkflowAppIds() {\n return useQuery<{ app_ids: string[] }>({\n queryKey: ['yamlWorkflowAppIds'],\n queryFn: () => apiFetch('/yaml-workflows/app-ids'),\n });\n}\n\nexport function useYamlWorkflowByTopic(graphTopic: string | undefined, appId?: string) {\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', 'byTopic', graphTopic, appId],\n queryFn: () => {\n const params = new URLSearchParams({ graph_topic: graphTopic!, limit: '1' });\n if (appId) params.set('app_id', appId);\n return apiFetch(`/yaml-workflows?${params}`);\n },\n enabled: !!graphTopic,\n });\n}\n\nexport function useYamlWorkflow(id: string) {\n return useQuery<LTYamlWorkflowRecord>({\n queryKey: ['yamlWorkflows', id],\n queryFn: () => apiFetch(`/yaml-workflows/${id}`),\n enabled: !!id,\n });\n}\n\nexport function useCreateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (input: {\n workflow_id: string;\n task_queue: string;\n workflow_name: string;\n name: string;\n description?: string;\n app_id?: string;\n subscribes?: string;\n tags?: string[];\n compilation_feedback?: string;\n }) =>\n apiFetch<LTYamlWorkflowRecord>('/yaml-workflows', {\n method: 'POST',\n body: JSON.stringify(input),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeployYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/deploy`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useActivateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/activate`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, data, sync, execute_as }: { id: string; data: Record<string, unknown>; sync?: boolean; execute_as?: string }) =>\n apiFetch<{ result?: unknown; job_id?: string }>(`/yaml-workflows/${id}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, sync, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRegenerateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, task_queue, compilation_feedback }: { id: string; task_queue?: string; compilation_feedback?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/regenerate`, {\n method: 'POST',\n body: JSON.stringify({ task_queue, compilation_feedback }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useArchiveYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/archive`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRestoreYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/restore`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflow'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpdateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, ...updates }: { id: string; yaml_content?: string; name?: string; description?: string; input_schema?: Record<string, unknown>; output_schema?: Record<string, unknown>; tags?: string[]; app_id?: string; graph_topic?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}`, {\n method: 'PUT',\n body: JSON.stringify(updates),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<{ deleted: boolean }>(`/yaml-workflows/${id}`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Cron scheduling ─────────────────────────────────────────────\n\nexport function useSetYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, cron_schedule, cron_envelope, execute_as }: {\n id: string;\n cron_schedule: string;\n cron_envelope?: Record<string, unknown> | null;\n execute_as?: string | null;\n }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'PUT',\n body: JSON.stringify({ cron_schedule, cron_envelope, execute_as }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useClearYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Version history ─────────────────────────────────────────────\n\nexport function useYamlWorkflowVersions(id: string) {\n return useQuery<{ versions: LTYamlWorkflowVersion[]; total: number }>({\n queryKey: ['yamlWorkflows', id, 'versions'],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions`),\n enabled: !!id,\n });\n}\n\nexport function useYamlWorkflowVersion(id: string, version: number | null) {\n return useQuery<LTYamlWorkflowVersion>({\n queryKey: ['yamlWorkflows', id, 'versions', version],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions/${version}`),\n enabled: !!id && version !== null,\n });\n}\n"],"names":["useYamlWorkflows","filters","params","useQuery","apiFetch","useYamlWorkflowAppIds","useYamlWorkflow","id","useCreateYamlWorkflow","queryClient","useQueryClient","useMutation","input","useDeployYamlWorkflow","useActivateYamlWorkflow","useInvokeYamlWorkflow","data","sync","execute_as","useRegenerateYamlWorkflow","task_queue","compilation_feedback","useArchiveYamlWorkflow","useRestoreYamlWorkflow","useUpdateYamlWorkflow","updates","useDeleteYamlWorkflow","useYamlWorkflowVersions","useYamlWorkflowVersion","version"],"mappings":"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"}
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
9
9
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
10
10
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
|
11
|
-
<script type="module" crossorigin src="./assets/index-
|
|
11
|
+
<script type="module" crossorigin src="./assets/index-CKXSKsVZ.js"></script>
|
|
12
12
|
<link rel="modulepreload" crossorigin href="./assets/vendor-query-B2UbickB.js">
|
|
13
13
|
<link rel="modulepreload" crossorigin href="./assets/vendor-react-CXumBFUA.js">
|
|
14
|
-
<link rel="modulepreload" crossorigin href="./assets/vendor-icons-
|
|
15
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
14
|
+
<link rel="modulepreload" crossorigin href="./assets/vendor-icons-BaQqUm-e.js">
|
|
15
|
+
<link rel="stylesheet" crossorigin href="./assets/index-CZ6-l8_0.css">
|
|
16
16
|
</head>
|
|
17
17
|
<body>
|
|
18
18
|
<div id="root"></div>
|
|
@@ -445,7 +445,7 @@ RBAC: `superadmin` sees all stations; other roles see only stations for their as
|
|
|
445
445
|
"pending": 12,
|
|
446
446
|
"claimed": 3,
|
|
447
447
|
"resolved": 45,
|
|
448
|
-
"
|
|
448
|
+
"priority_count": 2,
|
|
449
449
|
"throughput_pct": 112.5,
|
|
450
450
|
"wait": {
|
|
451
451
|
"p99": 18.3,
|
|
@@ -472,7 +472,7 @@ RBAC: `superadmin` sees all stations; other roles see only stations for their as
|
|
|
472
472
|
| `pending` | `number` | Escalations currently pending (real-time) |
|
|
473
473
|
| `claimed` | `number` | Escalations actively claimed (real-time) |
|
|
474
474
|
| `resolved` | `number` | Escalations resolved within the selected period |
|
|
475
|
-
| `
|
|
475
|
+
| `priority_count` | `number` | Pending, unclaimed escalations past the role's age threshold — the Pace Board rebalance signal |
|
|
476
476
|
| `throughput_pct` | `number \| null` | `resolved / (target_per_hour × period_hours) × 100`. `null` when the role has no `target_per_hour` set |
|
|
477
477
|
| `wait.p99` | `number \| null` | 99th-percentile wait time in minutes (creation → first claim) within the period. `null` when no resolved items |
|
|
478
478
|
| `wait.p50` | `number \| null` | Median wait time in minutes |
|
|
@@ -486,7 +486,7 @@ RBAC: `superadmin` sees all stations; other roles see only stations for their as
|
|
|
486
486
|
**Notes:**
|
|
487
487
|
- `pending` and `claimed` reflect the live queue state, not the selected period.
|
|
488
488
|
- `throughput_pct` above 100 means the station resolved more than its target — ahead of schedule. Below 100 means behind.
|
|
489
|
-
- `
|
|
489
|
+
- `priority_count` measures age from the role's `priority_facet` metadata timestamp (`created_at` when unset) against `priority_threshold_minutes` (`sla_minutes` when unset); it is 0 when neither threshold is configured. Claimed items are excluded. With a facet configured, items missing the key or holding an unparseable value are not counted.
|
|
490
490
|
- Time values are in decimal minutes.
|
|
491
491
|
|
|
492
492
|
**Example:** Fetch station metrics for the last hour:
|
|
@@ -667,7 +667,7 @@ Reassign multiple escalations to a different role. Requires admin or superadmin
|
|
|
667
667
|
POST /api/escalations/bulk-triage
|
|
668
668
|
```
|
|
669
669
|
|
|
670
|
-
Resolve multiple escalations and start AI triage workflows (mcpTriage) for each. Requires admin or superadmin permission for the escalation roles.
|
|
670
|
+
Resolve multiple escalations and start AI triage workflows (mcpTriage) for each. Rows backing a live `condition()` waiter (`signal_key` set) stay `pending` and are excluded from `triaged` — settle those individually via `POST /:id/resolve`, which carries the workflow's wake. Requires admin or superadmin permission for the escalation roles.
|
|
671
671
|
|
|
672
672
|
**Request body:**
|
|
673
673
|
|
|
@@ -1044,7 +1044,7 @@ Single atomic query finds the pending escalation by metadata, auto-claims if unc
|
|
|
1044
1044
|
POST /api/escalations/resolve-by-ids
|
|
1045
1045
|
```
|
|
1046
1046
|
|
|
1047
|
-
Resolve many escalations in one guarded statement — the set-based sibling of `POST /:id/resolve`. Used for bookkeeping rows that are woken collectively (it does not deliver a per-row signal). RBAC: a scoped caller may only resolve rows whose role they hold (global principals are unrestricted).
|
|
1047
|
+
Resolve many escalations in one guarded statement — the set-based sibling of `POST /:id/resolve`. Used for bookkeeping rows that are woken collectively (it does not deliver a per-row signal). The store enforces this: rows backing a live `condition()` waiter (`signal_key` set) stay `pending` and are excluded from the response — settle those via `POST /:id/resolve`, which carries the wake. RBAC: a scoped caller may only resolve rows whose role they hold (global principals are unrestricted).
|
|
1048
1048
|
|
|
1049
1049
|
| Field | Type | Required | Description |
|
|
1050
1050
|
|-------|------|----------|-------------|
|
|
@@ -1052,7 +1052,7 @@ Resolve many escalations in one guarded statement — the set-based sibling of `
|
|
|
1052
1052
|
| `resolverPayload` | `object` | yes | Payload applied to every row |
|
|
1053
1053
|
| `metadata` | `object` | no | Outcome patch merged into each row's GIN-indexed metadata |
|
|
1054
1054
|
|
|
1055
|
-
**Response 200:** `{ "resolved": <count>, "escalationIds": [...] }` — only
|
|
1055
|
+
**Response 200:** `{ "resolved": <count>, "escalationIds": [...] }` — only still-`pending` rows without a `signal_key` are resolved and returned.
|
|
1056
1056
|
|
|
1057
1057
|
## Faceted search
|
|
1058
1058
|
|
package/docs/api/http/roles.md
CHANGED
|
@@ -250,6 +250,8 @@ Returns all roles with metadata and usage counts.
|
|
|
250
250
|
"sla_minutes": 30,
|
|
251
251
|
"target_per_hour": 20,
|
|
252
252
|
"worker_count": 4,
|
|
253
|
+
"priority_threshold_minutes": null,
|
|
254
|
+
"priority_facet": null,
|
|
253
255
|
"user_count": 5,
|
|
254
256
|
"chain_count": 2,
|
|
255
257
|
"workflow_count": 3
|
|
@@ -270,6 +272,8 @@ Returns all roles with metadata and usage counts.
|
|
|
270
272
|
| `sla_minutes` | `number \| null` | Target resolution time in minutes (capacity setting) |
|
|
271
273
|
| `target_per_hour` | `number \| null` | Intended throughput — items resolved per hour (capacity setting) |
|
|
272
274
|
| `worker_count` | `number \| null` | Capacity at this station — staff or machine count (capacity setting) |
|
|
275
|
+
| `priority_threshold_minutes` | `number \| null` | Max age (minutes) before a pending unclaimed item counts toward `priority_count` in station metrics; falls back to `sla_minutes` |
|
|
276
|
+
| `priority_facet` | `string \| null` | Escalation metadata key holding the age origin as an ISO 8601 UTC timestamp (e.g. `authorized_at`); falls back to `created_at` |
|
|
273
277
|
| `user_count` | `number` | Number of users assigned this role |
|
|
274
278
|
| `chain_count` | `number` | Number of escalation chain entries referencing this role |
|
|
275
279
|
| `workflow_count` | `number` | Number of workflow configs that reference this role |
|
|
@@ -366,6 +370,8 @@ When the update changes `form_schema` or `metadata_schema`, the new pair is snap
|
|
|
366
370
|
| `sla_minutes` | `number \| null` | SLA target in minutes |
|
|
367
371
|
| `target_per_hour` | `number \| null` | Throughput target (items per hour) |
|
|
368
372
|
| `worker_count` | `number \| null` | Station capacity |
|
|
373
|
+
| `priority_threshold_minutes` | `number \| null` | Priority age threshold in minutes; falls back to `sla_minutes` |
|
|
374
|
+
| `priority_facet` | `string \| null` | Metadata key for the priority age origin (letters, numbers, underscores); falls back to `created_at` |
|
|
369
375
|
| `upstream_roles` | `string[] \| null` | Replace the set of roles this station draws input from across other Operations sequences (omitted = preserve; `null` or `[]` = clear). Every entry must name an existing role other than this one. Distinct from `parent_role`, which places the role in its own sequence. |
|
|
370
376
|
| `change_summary` | `string` | Label recorded on the schema version snapshot when this update changes a schema field |
|
|
371
377
|
|
|
@@ -130,10 +130,11 @@ PUT /api/workflows/:type/config
|
|
|
130
130
|
| Field | Type | Default | Description |
|
|
131
131
|
|-------|------|---------|-------------|
|
|
132
132
|
| `invocable` | `boolean` | `false` | Allow this workflow to be started via `POST /api/workflows/:type/invoke` |
|
|
133
|
+
| `certified` | `boolean` | derived | Explicit HITL certification (interceptor treatment). Omitted → derived from roles/consumes presence. |
|
|
133
134
|
| `task_queue` | `string \| null` | `null` | Task queue name (required for invocable workflows) |
|
|
134
135
|
| `default_role` | `string` | `"reviewer"` | Role assigned to escalations when the workflow doesn't specify one |
|
|
135
136
|
| `description` | `string \| null` | `null` | Human-readable description |
|
|
136
|
-
| `roles` | `string[]` | `[]` |
|
|
137
|
+
| `roles` | `string[]` | `[]` | Interceptor default for who can claim interceptor-raised escalations. Escalations raised in workflow code choose their own role, whose versioned schema takes precedence. |
|
|
137
138
|
| `invocation_roles` | `string[]` | `[]` | Roles allowed to invoke via API. Empty = any authenticated user. |
|
|
138
139
|
| `consumes` | `string[]` | `[]` | Workflow types whose completed data this workflow receives via `envelope.lt.providers` |
|
|
139
140
|
| `execute_as` | `string \| null` | `null` | Service account `external_id` to run as (overrides invoker identity) |
|
package/docs/api/mcp/admin.md
CHANGED
|
@@ -15,7 +15,7 @@ Each tool below is marked **Read-safe**. A service-account key scoped `mcp:read`
|
|
|
15
15
|
|
|
16
16
|
## Compile Hints
|
|
17
17
|
|
|
18
|
-
Admin tools modify system configuration.
|
|
18
|
+
Admin tools modify system configuration. upsert_workflow_config's `certified` flag and delete_workflow_config change interceptor behavior.
|
|
19
19
|
|
|
20
20
|
## Tasks
|
|
21
21
|
|
|
@@ -231,7 +231,10 @@ Release all escalation claims that exceeded their lock duration.
|
|
|
231
231
|
|
|
232
232
|
### bulk_triage
|
|
233
233
|
|
|
234
|
-
Resolve escalations for triage and start mcpTriage workflows.
|
|
234
|
+
Resolve escalations for triage and start mcpTriage workflows. Rows backing a
|
|
235
|
+
live `condition()` waiter (`signal_key` set) stay `pending` and are excluded
|
|
236
|
+
from the result — settle those with the targeted resolve, which carries the
|
|
237
|
+
workflow's wake.
|
|
235
238
|
|
|
236
239
|
| | |
|
|
237
240
|
|---|---|
|
|
@@ -400,11 +403,12 @@ Create or replace a workflow configuration (certify). Activates the interceptor
|
|
|
400
403
|
|-------|------|----------|-------------|
|
|
401
404
|
| workflow_type | string | Yes | Workflow type identifier |
|
|
402
405
|
| invocable | boolean | No | Whether the workflow can be invoked externally |
|
|
406
|
+
| certified | boolean | No | Explicit HITL certification (interceptor treatment). Omitted → derived from roles/consumes presence. |
|
|
403
407
|
| task_queue | string | No | HotMesh task queue |
|
|
404
408
|
| default_role | string | No | Default escalation role |
|
|
405
409
|
| description | string | No | Workflow description |
|
|
406
410
|
| execute_as | string | No | Execution identity |
|
|
407
|
-
| roles | string[] | No |
|
|
411
|
+
| roles | string[] | No | Interceptor default for who resolves interceptor-raised escalations |
|
|
408
412
|
| invocation_roles | string[] | No | Roles allowed to invoke |
|
|
409
413
|
| consumes | string[] | No | Event topics consumed |
|
|
410
414
|
| tool_tags | string[] | No | Tool tags for routing |
|
|
@@ -412,7 +416,7 @@ Create or replace a workflow configuration (certify). Activates the interceptor
|
|
|
412
416
|
|
|
413
417
|
### delete_workflow_config
|
|
414
418
|
|
|
415
|
-
|
|
419
|
+
Unregister a workflow by deleting its config entry. To demote certified → registered while keeping the registration, use `upsert_workflow_config` with `certified: false`.
|
|
416
420
|
|
|
417
421
|
| | |
|
|
418
422
|
|---|---|
|
|
@@ -745,6 +749,8 @@ Update a role's metadata: display name, description, form schema, metadata schem
|
|
|
745
749
|
| `sla_minutes` | `number \| null` | No | Target resolution time in minutes |
|
|
746
750
|
| `target_per_hour` | `number \| null` | No | Throughput goal (items resolved per hour) |
|
|
747
751
|
| `worker_count` | `number \| null` | No | Station capacity (staff or machines) |
|
|
752
|
+
| `priority_threshold_minutes` | `number \| null` | No | Priority age threshold in minutes; falls back to `sla_minutes` |
|
|
753
|
+
| `priority_facet` | `string \| null` | No | Metadata key for the priority age origin (ISO 8601 UTC); falls back to `created_at` |
|
|
748
754
|
| `upstream_roles` | `string[] \| null` | No | Replace the set of roles this station draws input from across other Operations sequences (omitted = preserve; `null` or `[]` = clear) |
|
|
749
755
|
| `change_summary` | `string` | No | Label recorded on the schema version snapshot when this update changes a schema field |
|
|
750
756
|
|
|
@@ -1158,10 +1164,12 @@ happened and where to look, not how to "fix" a job.
|
|
|
1158
1164
|
**Read this first — what is and isn't a problem.** A workflow suspended at a
|
|
1159
1165
|
`condition()` / `waitFor()` / `sleepFor()` can sit idle for days legitimately,
|
|
1160
1166
|
and HotMesh only bumps `updated_at` when a job's status changes. A frozen
|
|
1161
|
-
`updated_at` is therefore the *normal* signature of a wait, **not** a fault.
|
|
1167
|
+
`updated_at` is therefore the *normal* signature of a wait, **not** a fault. A
|
|
1168
|
+
reservation whose holder died self-heals: the message redelivers once the
|
|
1169
|
+
reclaim window lapses (~90s worst case) and the activity re-executes. The
|
|
1162
1170
|
genuinely broken signals are: a dead-lettered message (retries exhausted), a
|
|
1163
|
-
reservation
|
|
1164
|
-
|
|
1171
|
+
reservation still held past several reclaim windows, and a suspended waiter
|
|
1172
|
+
with **no** escalation row.
|
|
1165
1173
|
|
|
1166
1174
|
**Recommended flow:** start fleet-wide with `find_orphaned_signals` (the
|
|
1167
1175
|
genuinely-broken case) or `find_stalled_jobs` (candidates worth a look), then run
|
|
@@ -635,6 +635,8 @@ Trigger AI triage for multiple escalations.
|
|
|
635
635
|
|
|
636
636
|
Resolves each escalation and starts a triage workflow that uses MCP tools to analyze and potentially auto-resolve the issue.
|
|
637
637
|
|
|
638
|
+
Rows backing a live `condition()` waiter (`signal_key` set) stay `pending` and are excluded from `triaged` — their resolution must carry the workflow's wake, which only the targeted `resolve` delivers. Settle those individually with `resolve` or `cancel`.
|
|
639
|
+
|
|
638
640
|
```typescript
|
|
639
641
|
const result = await lt.escalations.bulkTriage({
|
|
640
642
|
ids: ['esc_1', 'esc_2'],
|
|
@@ -803,7 +805,7 @@ const result = await lt.escalations.resolveByMetadata({
|
|
|
803
805
|
|
|
804
806
|
## resolveByIds
|
|
805
807
|
|
|
806
|
-
Resolve a set of escalations by id in one guarded statement (the set-based sibling of `resolve`). For bookkeeping rows woken collectively — it does not deliver a per-row signal. RBAC: a scoped caller may only resolve rows whose role they hold.
|
|
808
|
+
Resolve a set of escalations by id in one guarded statement (the set-based sibling of `resolve`). For bookkeeping rows woken collectively — it does not deliver a per-row signal, and the store enforces that: rows backing a live `condition()` waiter (`signal_key` set) stay `pending` and are excluded from the result. Settle waiter rows individually with `resolve`, which carries the wake. RBAC: a scoped caller may only resolve rows whose role they hold.
|
|
807
809
|
|
|
808
810
|
```typescript
|
|
809
811
|
const result = await lt.escalations.resolveByIds({
|
|
@@ -911,13 +913,13 @@ interface StationMetric {
|
|
|
911
913
|
pending: number; // currently queued (status = pending and not claimed)
|
|
912
914
|
claimed: number; // active — claimed and assignment not expired
|
|
913
915
|
resolved: number; // resolved within the lookback period
|
|
914
|
-
|
|
916
|
+
priority_count: number; // pending unclaimed items past the role's age threshold
|
|
915
917
|
throughput_pct: number | null; // resolved / (target_per_hour × hours) × 100
|
|
916
918
|
wait: StationMetricPeriod; // queue time: created_at → claimed_at
|
|
917
919
|
work: StationMetricPeriod; // processing time: claimed_at → resolved_at
|
|
918
920
|
}
|
|
919
921
|
```
|
|
920
922
|
|
|
921
|
-
`pending` reflects the live queue depth regardless of period. `claimed`, `resolved`, and both percentile objects use the lookback window. `
|
|
923
|
+
`pending` reflects the live queue depth regardless of period. `claimed`, `resolved`, and both percentile objects use the lookback window. `priority_count` covers pending, unclaimed items whose age exceeds the role's threshold — age from the `priority_facet` metadata timestamp (`created_at` when unset) against `priority_threshold_minutes` (`sla_minutes` when unset); stations with neither threshold always return `0`. `throughput_pct` is `null` when `target_per_hour` is not set.
|
|
922
924
|
|
|
923
925
|
**Auth:** Same RBAC as `getStats` — callers see only the stations for roles they hold.
|
package/docs/api/sdk/roles.md
CHANGED
|
@@ -30,6 +30,8 @@ interface RoleDetail {
|
|
|
30
30
|
sla_minutes: number | null;
|
|
31
31
|
target_per_hour: number | null;
|
|
32
32
|
worker_count: number | null;
|
|
33
|
+
priority_threshold_minutes: number | null;
|
|
34
|
+
priority_facet: string | null;
|
|
33
35
|
user_count: number;
|
|
34
36
|
chain_count: number;
|
|
35
37
|
workflow_count: number;
|
|
@@ -46,9 +48,11 @@ interface RoleDetail {
|
|
|
46
48
|
| `properties` | Free user-owned bag — arbitrary config stored on the role |
|
|
47
49
|
| `ops_visible` | When `true`, the role appears as a station on the Operations view |
|
|
48
50
|
| `parent_role` | Parent role in the process dependency graph; drives the pace chart dependency ordering |
|
|
49
|
-
| `sla_minutes` | SLA target in minutes —
|
|
51
|
+
| `sla_minutes` | SLA target in minutes — the default age threshold for `priority_count` in station metrics |
|
|
50
52
|
| `target_per_hour` | Throughput target used to compute `throughput_pct` in station metrics |
|
|
51
53
|
| `worker_count` | Station capacity — number of workers expected to be active |
|
|
54
|
+
| `priority_threshold_minutes` | Max age before a pending unclaimed item counts toward `priority_count`; falls back to `sla_minutes` |
|
|
55
|
+
| `priority_facet` | Escalation metadata key holding the age origin as an ISO 8601 UTC timestamp (e.g. `authorized_at`); falls back to `created_at` |
|
|
52
56
|
| `user_count` | Number of users currently assigned to this role |
|
|
53
57
|
| `chain_count` | Number of escalation chain links originating from this role |
|
|
54
58
|
| `workflow_count` | Number of registered workflows that target this role |
|
|
@@ -269,6 +273,8 @@ const result = await lt.roles.update({
|
|
|
269
273
|
| `sla_minutes` | `number \| null` | No | SLA target in minutes |
|
|
270
274
|
| `target_per_hour` | `number \| null` | No | Throughput target (items per hour) |
|
|
271
275
|
| `worker_count` | `number \| null` | No | Station capacity |
|
|
276
|
+
| `priority_threshold_minutes` | `number \| null` | No | Priority age threshold in minutes; falls back to `sla_minutes` |
|
|
277
|
+
| `priority_facet` | `string \| null` | No | Metadata key for the priority age origin; falls back to `created_at` |
|
|
272
278
|
| `upstream_roles` | `string[] \| null` | No | Replace the set of roles this station draws input from across other Operations sequences (omitted = preserve; `null` or `[]` = clear). Distinct from `parent_role`, which places the role in its own sequence |
|
|
273
279
|
| `change_summary` | `string` | No | Label recorded on the schema version snapshot when this update changes a schema field |
|
|
274
280
|
|
|
@@ -152,7 +152,7 @@ const result = await lt.workflows.listDiscovered({ include_system: false });
|
|
|
152
152
|
|-------|------|----------|-------------|
|
|
153
153
|
| `include_system` | `boolean` | No | Include system workflows (default: false) |
|
|
154
154
|
|
|
155
|
-
**Returns:** `LTApiResult<{ workflows: [{ workflow_type, task_queue, registered, active, invocable, system, description, roles, invocation_roles, execute_as }] }>`
|
|
155
|
+
**Returns:** `LTApiResult<{ workflows: [{ workflow_type, task_queue, tier, registered, active, invocable, system, description, roles, invocation_roles, execute_as }] }>` — `tier` is `certified`, `registered`, or `durable`.
|
|
156
156
|
|
|
157
157
|
**Auth:** Not required
|
|
158
158
|
|
|
@@ -232,11 +232,12 @@ const result = await lt.workflows.upsertConfig({
|
|
|
232
232
|
|-------|------|----------|-------------|
|
|
233
233
|
| `type` | `string` | Yes | Workflow type name |
|
|
234
234
|
| `invocable` | `boolean` | No | Whether the workflow can be started via the API |
|
|
235
|
+
| `certified` | `boolean` | No | Explicit HITL certification (interceptor treatment). Omitted → derived from roles/consumes presence. |
|
|
235
236
|
| `task_queue` | `string \| null` | No | HotMesh task queue |
|
|
236
237
|
| `default_role` | `string` | No | Default escalation role |
|
|
237
238
|
| `description` | `string \| null` | No | Human-readable description |
|
|
238
239
|
| `execute_as` | `string \| null` | No | Service account for proxy invocation |
|
|
239
|
-
| `roles` | `string[]` | No |
|
|
240
|
+
| `roles` | `string[]` | No | Interceptor default for who resolves interceptor-raised escalations |
|
|
240
241
|
| `invocation_roles` | `string[]` | No | Roles that can invoke this workflow |
|
|
241
242
|
| `consumes` | `string[]` | No | Workflow types whose data this workflow consumes |
|
|
242
243
|
| `tool_tags` | `string[]` | No | MCP tool tags for discovery |
|
package/docs/architecture.md
CHANGED
|
@@ -112,7 +112,7 @@ A durable workflow has no entry in `lt_config_workflows`. It runs, but without i
|
|
|
112
112
|
|
|
113
113
|
### Certified
|
|
114
114
|
|
|
115
|
-
A certified workflow is durable plus the full Long Tail control plane. It has an entry in `lt_config_workflows`, which activates:
|
|
115
|
+
A certified workflow is durable plus the full Long Tail control plane. It has an entry in `lt_config_workflows` with `certified: true`, which activates:
|
|
116
116
|
|
|
117
117
|
- **Interceptor wrapping** — every execution is tracked as a task in `lt_tasks` with full audit trail.
|
|
118
118
|
- **Escalation chains** — returning `{ type: 'escalation' }` creates a reviewable record, routes to the correct role, and triggers re-runs on resolution.
|
|
@@ -120,7 +120,7 @@ A certified workflow is durable plus the full Long Tail control plane. It has an
|
|
|
120
120
|
- **Invocation controls** — `invocable: true` exposes the workflow for external invocation via the API and dashboard.
|
|
121
121
|
- **Execution identity** — roles, default assignees, and `execute_as` overrides are defined in the config.
|
|
122
122
|
|
|
123
|
-
In the dashboard, certified workflows display a **ShieldCheck** icon with a "Certified" label in accent blue.
|
|
123
|
+
In the dashboard, certified workflows display a **ShieldCheck** icon with a "Certified" label in accent blue. A registration without certification ("Registered" tier) keeps invocation controls and schema-driven forms while skipping the interceptor. Certification is the `certified` flag on the registration: promote by checking Certify (or `certified: true` in the config), demote by unchecking it — escalation roles and dependencies stay on the row. Unregistering deletes the entry entirely. The workflow code does not change.
|
|
124
124
|
|
|
125
125
|
### Pipeline
|
|
126
126
|
|
package/docs/dashboard.md
CHANGED
|
@@ -64,15 +64,15 @@ The top navigation bar contains:
|
|
|
64
64
|
|
|
65
65
|
### Workflow Registry
|
|
66
66
|
|
|
67
|
-
Shows every workflow the system has discovered across all registered workers. Each workflow displays one of three tiers:
|
|
67
|
+
Shows every workflow the system has discovered across all registered workers. Each workflow displays one of three tiers — direct states of the registration:
|
|
68
68
|
|
|
69
|
-
- **Certified** (ShieldCheck icon) — has an `lt_config_workflows` entry with
|
|
70
|
-
- **
|
|
71
|
-
- **Durable** (Wrench icon) —
|
|
69
|
+
- **Certified** (ShieldCheck icon) — has an `lt_config_workflows` entry with `certified: true`. Full interceptor tracking, escalation defaults, and invocation controls.
|
|
70
|
+
- **Registered** (Settings icon) — has a registration with `certified: false`. Invocation controls and schema-driven forms, without interceptor wrapping.
|
|
71
|
+
- **Durable** (Wrench icon) — runs as a HotMesh worker with no registration. Checkpointed execution and retries only.
|
|
72
72
|
|
|
73
73
|
**Columns:** Workflow (pill + description), Queue (bordered pill), Tier (icon + label), Access (escalation roles with shield icon, invocation roles with user-check icon).
|
|
74
74
|
|
|
75
|
-
**Row actions** (on hover): Play (invoke), Wrench (
|
|
75
|
+
**Row actions** (on hover): Play (invoke), Wrench (register durable), ShieldPlus (certify registered), ShieldOff (unregister — deletes the registration). To demote certified → registered, open the workflow and uncheck **Certify for HITL Escalation**; escalation roles, dependencies, and schemas stay on the registration.
|
|
76
76
|
|
|
77
77
|
**Inline config via `start()`:** Developers can declare workflow profiles directly in the `start()` config by adding a `config` block to any worker entry. This auto-seeds the workflow into `lt_config_workflows` at startup — no manual API calls or dashboard wizard needed. Roles referenced in the config are auto-created.
|
|
78
78
|
|
|
@@ -84,6 +84,7 @@ workers: [
|
|
|
84
84
|
config: {
|
|
85
85
|
description: 'My workflow description',
|
|
86
86
|
invocable: true,
|
|
87
|
+
certified: true,
|
|
87
88
|
roles: ['reviewer', 'admin'],
|
|
88
89
|
envelopeSchema: { data: { field1: '', field2: 0 } },
|
|
89
90
|
resolverSchema: { approved: true, notes: '' },
|
|
@@ -217,7 +218,7 @@ Search filters by key, label, or description. **+ Add Role** creates a role here
|
|
|
217
218
|
|
|
218
219
|
Accessible at `/admin/roles/:role`. One page per role — a header plus three columns covering identity, routing and people, and schemas.
|
|
219
220
|
|
|
220
|
-
**Header** — the role key with its prior step, the capacity set, and the **Ops** toggle that shows the role as a station on the [Pace Board](#pace-board). The capacity set holds `sla_minutes`, `target_per_hour`, and `worker_count`; enter any two and the header hints the derived third (`throughput = workers / (sla / 60)`). Save applies header and identity edits via `PATCH /api/roles/:role`.
|
|
221
|
+
**Header** — the role key with its prior step, the capacity set, and the **Ops** toggle that shows the role as a station on the [Pace Board](#pace-board). The capacity set holds `sla_minutes`, `target_per_hour`, and `worker_count`; enter any two and the header hints the derived third (`throughput = workers / (sla / 60)`). Beside it, the priority set holds `priority_threshold_minutes` and `priority_facet` — the age threshold and metadata timestamp key driving the Pace Board priority count (blank = `sla_minutes` and `created_at`). Save applies header and identity edits via `PATCH /api/roles/:role`.
|
|
221
222
|
|
|
222
223
|
**Identity** — display name and description, shown on role rows and station labels.
|
|
223
224
|
|
|
@@ -314,13 +315,14 @@ Execution is a graph; this page tells its story as **sequences**. Each station r
|
|
|
314
315
|
|
|
315
316
|
- **Sequence picker** — when more than one sequence exists, tabs appear above the chart, one per sequence, named by its origin role with the station count alongside. The active sequence is deep-linked (`?fragment=<origin role>`) and each switch is a browser-history entry, so a shared URL opens the same sequence and back/forward walks between them.
|
|
316
317
|
- **Period selector** — `15m`, `1h`, `24h`, `7d`, `30d`. Controls the lookback window for resolved counts, percentile metrics, and throughput.
|
|
317
|
-
- **Pace chart** — connects the active sequence's stations in process dependency order and plots absolute counts for the selected window: a straight red target polyline (`target_per_hour × window hours`) against a smooth actual (resolved) curve with a light area fill. The queue splits into two stacked bands — claimed-and-worked (indigo) and waiting-unclaimed (sky). Station circles are colored by pace ratio (green ≥ 100%, amber ≥ 60%, red below)
|
|
318
|
+
- **Pace chart** — connects the active sequence's stations in process dependency order and plots absolute counts for the selected window: a straight red target polyline (`target_per_hour × window hours`) against a smooth actual (resolved) curve with a light area fill. The queue splits into two stacked bands — claimed-and-worked (indigo) and waiting-unclaimed (sky). Station circles are colored by pace ratio (green ≥ 100%, amber ≥ 60%, red below).
|
|
319
|
+
- **Priority badge** — a station with unclaimed items past its age threshold carries a powder-blue circle with the count. Age is measured from the role's priority facet (a metadata timestamp such as the order's authorized date; `created_at` when unset) against its priority threshold (`sla_minutes` when unset). Clicking the badge opens that station's queue ordered oldest-first by the same facet — the counted items sit at the top, ready to pull to the front of the rack.
|
|
318
320
|
- **Merge affordance** — a station that declares upstream inputs shows a small dashed merge glyph at its floor position. It is deliberately a symbol, never a bend in the line: the upstream is an input, not a descendant. Hover names the feeding roles; click jumps to their sequence.
|
|
319
|
-
- **Station table** — one row per station: ROLE (with a merge icon marking cross-sequence inputs), TARGET/H, then PENDING, ACTIVE, RESOLVED in column bands carrying the chart's hues, P99 WAIT, P99 WORK, and a TREND mini-bar. TREND shows the live backlog-to-target ratio while the queue has items; when the queue is idle it shows the period's throughput efficiency, marked with `↩`. Stations with
|
|
321
|
+
- **Station table** — one row per station: ROLE (with a merge icon marking cross-sequence inputs), TARGET/H, then PENDING, ACTIVE, RESOLVED in column bands carrying the chart's hues, P99 WAIT, P99 WORK, and a TREND mini-bar. TREND shows the live backlog-to-target ratio while the queue has items; when the queue is idle it shows the period's throughput efficiency, marked with `↩`. Stations with priority items show a powder-blue sub-row linking to the queue ordered oldest-first by the priority facet.
|
|
320
322
|
- **Station detail panel** — opens on row or circle click. Shows the role's identity, an independent period toggle, and the full metric breakdown (wait/work percentiles, SLA target, worker count, links to the queue).
|
|
321
323
|
- **Live updates** — escalation events refresh the metrics push-driven and debounced; the header's refresh button forces a reload.
|
|
322
324
|
|
|
323
|
-
A role joins the board via the **Ops** toggle on its [Role Detail](#role-detail) page; the capacity settings (`sla_minutes`, `target_per_hour`, `worker_count`) drive the computed metrics. See [Operations](operations.md) for the full concept doc.
|
|
325
|
+
A role joins the board via the **Ops** toggle on its [Role Detail](#role-detail) page; the capacity settings (`sla_minutes`, `target_per_hour`, `worker_count`) and the priority dials (`priority_threshold_minutes`, `priority_facet`) drive the computed metrics. See [Operations](operations.md) for the full concept doc.
|
|
324
326
|
|
|
325
327
|
**API:** `GET /api/escalations/station-metrics?period=24h`
|
|
326
328
|
|
package/docs/data.md
CHANGED
|
@@ -22,6 +22,8 @@ Canonical role registry. Roles referenced by other tables are seeded here.
|
|
|
22
22
|
| `sla_minutes` | `NUMERIC` | — | Target resolution time |
|
|
23
23
|
| `target_per_hour` | `NUMERIC` | — | Throughput target |
|
|
24
24
|
| `worker_count` | `NUMERIC` | — | Station capacity |
|
|
25
|
+
| `priority_threshold_minutes` | `NUMERIC` | — | Priority age threshold; falls back to `sla_minutes` |
|
|
26
|
+
| `priority_facet` | `TEXT` | — | Escalation metadata key holding the priority age origin (ISO 8601 UTC); falls back to `created_at` |
|
|
25
27
|
| `created_at` | `TIMESTAMPTZ NOT NULL` | `NOW()` | Row creation time |
|
|
26
28
|
|
|
27
29
|
**Seeds:** `reviewer`, `engineer`, `admin`, `superadmin`.
|
package/docs/iam.md
CHANGED
|
@@ -51,11 +51,11 @@ Long Tail has three workflow types (see the [Workflows Guide](workflows.md#three
|
|
|
51
51
|
|
|
52
52
|
**Durable workflows** are the baseline. Every workflow registered with HotMesh is durable: checkpointed to Postgres, restartable after crashes, with full IAM context. If an activity throws, the workflow fails.
|
|
53
53
|
|
|
54
|
-
**Certified workflows** add the interceptor. The interceptor wraps every execution so that failures escalate to a human reviewer instead of throwing. A certified workflow has an entry in `lt_config_workflows` that defines its escalation
|
|
54
|
+
**Certified workflows** add the interceptor. The interceptor wraps every execution so that failures escalate to a human reviewer instead of throwing. A certified workflow has an entry in `lt_config_workflows` with `certified: true` that defines its escalation defaults, invocation roles, and optional `execute_as` service account. It gets never-fail guarantees — when an LLM call returns garbage or an API is down, the workflow pauses and creates a human task rather than dying.
|
|
55
55
|
|
|
56
56
|
**Pipeline workflows** are compiled deterministic workflows that execute tool calls without an LLM. They inherit the IAM context of the invoking workflow — the principal, credentials, and trace lineage all propagate through the YAML DAG execution.
|
|
57
57
|
|
|
58
|
-
Any durable workflow can be promoted
|
|
58
|
+
Any durable workflow can be promoted through the Workflow Registry in the dashboard: registering creates the config entry (invocation + schemas), and the Certify checkbox turns on the interceptor. Unchecking Certify demotes to registered and keeps the config; unregistering deletes it. The workflow code does not change.
|
|
59
59
|
|
|
60
60
|
## Service Accounts
|
|
61
61
|
|
|
@@ -196,7 +196,7 @@ When an activity calls `getCredential('anthropic')` and no credential exists in
|
|
|
196
196
|
|
|
197
197
|
The dashboard surfaces IAM across four pages:
|
|
198
198
|
|
|
199
|
-
**Workflow Registry** (`/workflows/registry`) — lists all discovered workflows. Certified workflows display a ShieldCheck badge in accent blue; pipeline workflows display a Wand2 icon in purple; durable workflows show the standard Workflow icon. Use ShieldPlus to certify a
|
|
199
|
+
**Workflow Registry** (`/workflows/registry`) — lists all discovered workflows. Certified workflows display a ShieldCheck badge in accent blue; pipeline workflows display a Wand2 icon in purple; durable workflows show the standard Workflow icon. Use ShieldPlus to certify a registered workflow, the Certify checkbox on the detail page to promote or demote, and ShieldOff to unregister.
|
|
200
200
|
|
|
201
201
|
**Accounts** (`/admin/users`) — unified management for User Accounts and Service Accounts via tab toggle. Create service accounts, assign roles, generate API keys. The key generation flow displays the raw key once; it cannot be retrieved after dismissal.
|
|
202
202
|
|
package/docs/operations.md
CHANGED
|
@@ -14,12 +14,25 @@ Each station has three settings that define what "healthy" looks like — knowin
|
|
|
14
14
|
|
|
15
15
|
| Field | Description |
|
|
16
16
|
|-------|-------------|
|
|
17
|
-
| `sla_minutes` | Target resolution time in minutes.
|
|
17
|
+
| `sla_minutes` | Target resolution time in minutes. The default age threshold for the priority count. |
|
|
18
18
|
| `target_per_hour` | Intended throughput — how many items should resolve per hour. Used to compute `throughput_pct` and the station's expected count on the pace chart. |
|
|
19
19
|
| `worker_count` | Capacity at this station — number of staff or machines expected to be active. |
|
|
20
20
|
|
|
21
21
|
These are set via `PATCH /api/roles/:role` or the Roles admin page.
|
|
22
22
|
|
|
23
|
+
## Priority count
|
|
24
|
+
|
|
25
|
+
Every station carries one age signal: `priority_count`, the number of **pending, unclaimed** items older than the station's threshold. It is deliberately a count, not a re-sorted queue — the floor rebalances coarsely, pulling the counted items to the front of the rack, rather than continuously re-ordering everything.
|
|
26
|
+
|
|
27
|
+
Two per-role dials shape it, each with a fallback so the count works from `sla_minutes` alone:
|
|
28
|
+
|
|
29
|
+
| Dial | Description |
|
|
30
|
+
|------|-------------|
|
|
31
|
+
| `priority_facet` | `lt_escalations.metadata` key holding each item's age origin as an ISO 8601 UTC timestamp (e.g. `authorized_at`, the date the order was authorized). Blank = age from `created_at`. When set, items missing the key or holding an unparseable value are not counted. |
|
|
32
|
+
| `priority_threshold_minutes` | Max age before an item counts as priority. Blank = the station's `sla_minutes`. |
|
|
33
|
+
|
|
34
|
+
Claimed items are excluded — they are already in someone's hands; the count is what still needs pulling forward. On the pace chart the count renders as a powder-blue circle at the station; clicking it (or the sub-row link in the station table) opens the station's queue ordered oldest-first by the same facet, so the counted items sit at the top.
|
|
35
|
+
|
|
23
36
|
## Pace chart
|
|
24
37
|
|
|
25
38
|
The chart is the centrepiece. It plots **absolute counts for the selected window** across the pipeline — every station in dependency order (parent before children, breadth-first) on the X axis.
|
|
@@ -63,7 +76,7 @@ Below the chart, a flat table lists every station with its live numbers:
|
|
|
63
76
|
| P99 WORK | 99th-percentile processing time (claimed → resolved) in minutes |
|
|
64
77
|
| TREND | Mini fill bar + percentage — live backlog ratio while items queue, period throughput efficiency when idle |
|
|
65
78
|
|
|
66
|
-
If a station has `
|
|
79
|
+
If a station has `priority_count > 0`, a powder-blue sub-row appears: `N priority — pull oldest first →`. The link opens the escalation queue filtered to that role and ordered oldest-first by the station's priority facet (`created_at` when no facet is configured), so the counted items sit at the top.
|
|
67
80
|
|
|
68
81
|
Clicking any row opens the station detail panel.
|
|
69
82
|
|
|
@@ -79,7 +92,7 @@ Close the panel with × or by clicking another row.
|
|
|
79
92
|
|
|
80
93
|
## Data source
|
|
81
94
|
|
|
82
|
-
All station metrics come from `GET /api/escalations/station-metrics?period=<period>`. The endpoint runs two queries against `public.hmsh_escalations` joined to `lt_roles` (for
|
|
95
|
+
All station metrics come from `GET /api/escalations/station-metrics?period=<period>`. The endpoint runs two queries against `public.hmsh_escalations` joined to `lt_roles` (for the priority dials and `target_per_hour`): a live-counts pass over the pending backlog, and a window-bounded percentile pass over resolved rows (`PERCENTILE_CONT` in Postgres, served by the `idx_hmsh_esc_resolved_cover` index). Updates reach the page as push events — every escalation write invalidates the metrics through the Socket.IO event system.
|
|
83
96
|
|
|
84
97
|
`pending` is always the live count regardless of period. `resolved`, percentiles, and `throughput_pct` are scoped to the lookback window. See [`lt.escalations.getStationMetrics`](api/sdk/escalations.md#getstationmetrics) for the full response shape.
|
|
85
98
|
|