@hotmeshio/long-tail 0.1.8 → 0.1.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.js +40 -5
- package/build/api/tasks.d.ts +25 -1
- package/build/api/tasks.js +49 -0
- package/build/api/workflows.js +8 -1
- package/build/examples/seed.js +18 -0
- package/build/examples/types/envelopes.d.ts +8 -0
- package/build/examples/types/index.d.ts +1 -1
- package/build/examples/workers.js +2 -0
- package/build/examples/workflows/basic-signal/activities.d.ts +17 -0
- package/build/examples/workflows/basic-signal/activities.js +18 -0
- package/build/examples/workflows/basic-signal/index.d.ts +17 -0
- package/build/examples/workflows/basic-signal/index.js +116 -0
- package/build/index.d.ts +1 -0
- package/build/index.js +4 -1
- package/build/lib/db/schemas/002_seed.sql +9 -1
- package/build/modules/ltconfig.d.ts +8 -1
- package/build/modules/ltconfig.js +12 -2
- package/build/routes/tasks.js +23 -0
- package/build/routes/workflows/invocation.js +1 -1
- package/build/sdk/index.d.ts +15 -0
- package/build/sdk/index.js +1 -0
- package/build/services/interceptor/index.js +9 -3
- package/build/services/orchestrator/condition.d.ts +34 -0
- package/build/services/orchestrator/condition.js +92 -0
- package/build/services/workflow-invocation.d.ts +1 -1
- package/build/services/workflow-invocation.js +4 -1
- package/build/start/index.d.ts +24 -0
- package/build/start/index.js +24 -0
- package/build/start/workers.d.ts +6 -8
- package/build/start/workers.js +25 -2
- package/build/system/mcp-servers/admin/workflows.js +5 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/envelope.d.ts +7 -0
- package/build/types/sdk.d.ts +2 -0
- package/build/types/startup.d.ts +29 -2
- package/dashboard/dist/assets/{AdminDashboard-B15jSEV2.js → AdminDashboard-DUrSBQOl.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-B15jSEV2.js.map → AdminDashboard-DUrSBQOl.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-0V2yvKak.js → AvailableEscalationsPage-Dbd1qUK_.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-0V2yvKak.js.map → AvailableEscalationsPage-Dbd1qUK_.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-B4UxHcek.js → BotPicker-Cg5iNEkm.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-B4UxHcek.js.map → BotPicker-Cg5iNEkm.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-BBexNWVd.js → CollapsibleSection-Kd9UIyeU.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-BBexNWVd.js.map → CollapsibleSection-Kd9UIyeU.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-DlPDJSq_.js → ConfirmDeleteModal-DZMgmlof.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-DlPDJSq_.js.map → ConfirmDeleteModal-DZMgmlof.js.map} +1 -1
- package/dashboard/dist/assets/{CopyableId-BxHW1ahb.js → CopyableId-cPFTRm8q.js} +2 -2
- package/dashboard/dist/assets/{CopyableId-BxHW1ahb.js.map → CopyableId-cPFTRm8q.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-Bp_Y1Szk.js → CredentialsPage-DJablIbs.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-Bp_Y1Szk.js.map → CredentialsPage-DJablIbs.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-ByBFqXSO.js → CustomDurationPicker-NgIP6YDW.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-ByBFqXSO.js.map → CustomDurationPicker-NgIP6YDW.js.map} +1 -1
- package/dashboard/dist/assets/{DataTable-DyIXg-tQ.js → DataTable-CTRhTAfT.js} +2 -2
- package/dashboard/dist/assets/{DataTable-DyIXg-tQ.js.map → DataTable-CTRhTAfT.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-BgnA0qpS.js → ElapsedCell-HcSJ_MMs.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-BgnA0qpS.js.map → ElapsedCell-HcSJ_MMs.js.map} +1 -1
- package/dashboard/dist/assets/{EmptyState-DlMImvgm.js → EmptyState-joNbd4gg.js} +2 -2
- package/dashboard/dist/assets/{EmptyState-DlMImvgm.js.map → EmptyState-joNbd4gg.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-D90kdfw1.js → EscalationsOverview-DpXDnQux.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-D90kdfw1.js.map → EscalationsOverview-DpXDnQux.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-BNxtlgNz.js → EventTable-CYem3v8n.js} +2 -2
- package/dashboard/dist/assets/{EventTable-BNxtlgNz.js.map → EventTable-CYem3v8n.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-BTiaAhCx.js → FilterBar-BiO8SOzc.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-BTiaAhCx.js.map → FilterBar-BiO8SOzc.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-BUcagSCn.js → ListToolbar-6yRDh2e9.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-BUcagSCn.js.map → ListToolbar-6yRDh2e9.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-B-tCvz8C.js → McpOverview-CUgSxkQe.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-B-tCvz8C.js.map → McpOverview-CUgSxkQe.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-DPlF1wYb.js → McpQueryDetailPage-BWbinTM_.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-DPlF1wYb.js.map → McpQueryDetailPage-BWbinTM_.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-Bz7AdcfR.js → McpQueryPage-lV6kfDG5.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-Bz7AdcfR.js.map → McpQueryPage-lV6kfDG5.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-Di_qpL2V.js → McpRunDetailPage-D6gaxH3_.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-Di_qpL2V.js.map → McpRunDetailPage-D6gaxH3_.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-BBgybBEa.js → McpRunsPage-DKvTklh9.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-BBgybBEa.js.map → McpRunsPage-DKvTklh9.js.map} +1 -1
- package/dashboard/dist/assets/{Modal-CaJ0gTEa.js → Modal-BuTvD0pz.js} +2 -2
- package/dashboard/dist/assets/{Modal-CaJ0gTEa.js.map → Modal-BuTvD0pz.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-DDfMmrmR.js → OperatorDashboard-C9SSV96T.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-DDfMmrmR.js.map → OperatorDashboard-C9SSV96T.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-C5D-G5rp.js → PageHeader-BcTVF9ul.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-C5D-G5rp.js.map → PageHeader-BcTVF9ul.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-DCa2eZh2.js → PageHeaderWithStats-BI7JG5x6.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-DCa2eZh2.js.map → PageHeaderWithStats-BI7JG5x6.js.map} +1 -1
- package/dashboard/dist/assets/{PriorityBadge-DTHq6OUZ.js → PriorityBadge-DqVaOU65.js} +2 -2
- package/dashboard/dist/assets/{PriorityBadge-DTHq6OUZ.js.map → PriorityBadge-DqVaOU65.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-fC4dhrd0.js → ProcessDetailPage-hFMhf9qa.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-fC4dhrd0.js.map → ProcessDetailPage-hFMhf9qa.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-CL2MY8uD.js → ProcessesListPage-ByVoBCQ3.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-CL2MY8uD.js.map → ProcessesListPage-ByVoBCQ3.js.map} +1 -1
- package/dashboard/dist/assets/{RolePill-kgKPANly.js → RolePill-D9ZIkYiu.js} +2 -2
- package/dashboard/dist/assets/{RolePill-kgKPANly.js.map → RolePill-D9ZIkYiu.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-Be2lXTHD.js → RolesPage-SMedMuqa.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-Be2lXTHD.js.map → RolesPage-SMedMuqa.js.map} +1 -1
- package/dashboard/dist/assets/{RowActions-DIzJCwqR.js → RowActions-yDhwwDbU.js} +2 -2
- package/dashboard/dist/assets/{RowActions-DIzJCwqR.js.map → RowActions-yDhwwDbU.js.map} +1 -1
- package/dashboard/dist/assets/{StatCard-CRi2Jy6t.js → StatCard-BrBnQFxh.js} +2 -2
- package/dashboard/dist/assets/{StatCard-CRi2Jy6t.js.map → StatCard-BrBnQFxh.js.map} +1 -1
- package/dashboard/dist/assets/{StatusBadge-BETI_8Mr.js → StatusBadge-xgb-lZku.js} +2 -2
- package/dashboard/dist/assets/{StatusBadge-BETI_8Mr.js.map → StatusBadge-xgb-lZku.js.map} +1 -1
- package/dashboard/dist/assets/{StepIndicator-DjpMqCjz.js → StepIndicator-B9ps2SvM.js} +2 -2
- package/dashboard/dist/assets/{StepIndicator-DjpMqCjz.js.map → StepIndicator-B9ps2SvM.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-BZbExQ9t.js → StickyPagination-DTIjBKN3.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-BZbExQ9t.js.map → StickyPagination-DTIjBKN3.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-DZthQyhR.js → SwimlaneTimeline-RK4Yu66z.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-DZthQyhR.js.map → SwimlaneTimeline-RK4Yu66z.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-CukbOfYn.js → TagInput-CdNUuqk4.js} +2 -2
- package/dashboard/dist/assets/{TagInput-CukbOfYn.js.map → TagInput-CdNUuqk4.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-CIZHIKo9.js → TaskDetailPage-C-nzaNea.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-CIZHIKo9.js.map → TaskDetailPage-C-nzaNea.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-Q7DGoysj.js → TaskQueuePill-Lvr2-NzS.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-Q7DGoysj.js.map → TaskQueuePill-Lvr2-NzS.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-CsC9wjb0.js → TasksListPage-DSUmD84y.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-CsC9wjb0.js.map → TasksListPage-DSUmD84y.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-BcOOnJeH.js → TimeAgo-BZdLdrIh.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-BcOOnJeH.js.map → TimeAgo-BZdLdrIh.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-CEMapYDQ.js → TimestampCell-QX_0i5FK.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-CEMapYDQ.js.map → TimestampCell-QX_0i5FK.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-BHoN7iRL.js → UserName-DyZMXcBm.js} +2 -2
- package/dashboard/dist/assets/{UserName-BHoN7iRL.js.map → UserName-DyZMXcBm.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-DawKl1LT.js → WorkflowExecutionPage-DjVxfZaF.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-DawKl1LT.js.map → WorkflowExecutionPage-DjVxfZaF.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowPill-CZqGslD6.js +2 -0
- package/dashboard/dist/assets/WorkflowPill-CZqGslD6.js.map +1 -0
- package/dashboard/dist/assets/WorkflowsDashboard-DZjuiFZ0.js +2 -0
- package/dashboard/dist/assets/WorkflowsDashboard-DZjuiFZ0.js.map +1 -0
- package/dashboard/dist/assets/{WorkflowsOverview-DuhAi_OY.js → WorkflowsOverview-CLnLRpOu.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-DuhAi_OY.js.map → WorkflowsOverview-CLnLRpOu.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-Dc9xw82a.js → YamlWorkflowsPage-VjdhnLmO.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-Dc9xw82a.js.map → YamlWorkflowsPage-VjdhnLmO.js.map} +1 -1
- package/dashboard/dist/assets/{bots-Dny-rmmI.js → bots-DIM6lBoY.js} +2 -2
- package/dashboard/dist/assets/{bots-Dny-rmmI.js.map → bots-DIM6lBoY.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-CV0sKNH5.js → escalation-JOTuOqjq.js} +2 -2
- package/dashboard/dist/assets/{escalation-CV0sKNH5.js.map → escalation-JOTuOqjq.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-30CKyoWI.js → escalation-columns-Cyg58nkg.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-30CKyoWI.js.map → escalation-columns-Cyg58nkg.js.map} +1 -1
- package/dashboard/dist/assets/{helpers-C1-30CzH.js → helpers-B1BDxBZd.js} +2 -2
- package/dashboard/dist/assets/{helpers-C1-30CzH.js.map → helpers-B1BDxBZd.js.map} +1 -1
- package/dashboard/dist/assets/{helpers-C1jaRD-d.js → helpers-BCix9c_m.js} +2 -2
- package/dashboard/dist/assets/{helpers-C1jaRD-d.js.map → helpers-BCix9c_m.js.map} +1 -1
- package/dashboard/dist/assets/{index-D_aJBEAG.js → index-BUK3qR-1.js} +2 -2
- package/dashboard/dist/assets/{index-D_aJBEAG.js.map → index-BUK3qR-1.js.map} +1 -1
- package/dashboard/dist/assets/{index-DnmZbNxk.js → index-BYZX9tOb.js} +5 -5
- package/dashboard/dist/assets/index-BYZX9tOb.js.map +1 -0
- package/dashboard/dist/assets/{index-D-oCWCAS.js → index-BcR6PfpY.js} +2 -2
- package/dashboard/dist/assets/{index-D-oCWCAS.js.map → index-BcR6PfpY.js.map} +1 -1
- package/dashboard/dist/assets/index-BizfauqT.js +6 -0
- package/dashboard/dist/assets/index-BizfauqT.js.map +1 -0
- package/dashboard/dist/assets/{index-CxVB7F4X.js → index-Cf60K3x9.js} +2 -2
- package/dashboard/dist/assets/{index-CxVB7F4X.js.map → index-Cf60K3x9.js.map} +1 -1
- package/dashboard/dist/assets/{index-D0wPM3Ck.js → index-Cg5nfiYX.js} +2 -2
- package/dashboard/dist/assets/{index-D0wPM3Ck.js.map → index-Cg5nfiYX.js.map} +1 -1
- package/dashboard/dist/assets/index-D1wVX50Z.js +15 -0
- package/dashboard/dist/assets/index-D1wVX50Z.js.map +1 -0
- package/dashboard/dist/assets/{index-DHgnkykj.js → index-DDYFpi4l.js} +4 -4
- package/dashboard/dist/assets/index-DDYFpi4l.js.map +1 -0
- package/dashboard/dist/assets/{index-_RBvi7s6.js → index-Di12t56M.js} +2 -2
- package/dashboard/dist/assets/{index-_RBvi7s6.js.map → index-Di12t56M.js.map} +1 -1
- package/dashboard/dist/assets/{index-Dd_U4mLm.js → index-Ds0JoXS2.js} +2 -2
- package/dashboard/dist/assets/{index-Dd_U4mLm.js.map → index-Ds0JoXS2.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-CRFr4L9W.js → mcp-B_xbczAt.js} +2 -2
- package/dashboard/dist/assets/{mcp-CRFr4L9W.js.map → mcp-B_xbczAt.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-DHY2mZBQ.js → mcp-query-B8-P_QoG.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-DHY2mZBQ.js.map → mcp-query-B8-P_QoG.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-runs-BqPHqwAO.js → mcp-runs-CWeZinoF.js} +2 -2
- package/dashboard/dist/assets/{mcp-runs-BqPHqwAO.js.map → mcp-runs-CWeZinoF.js.map} +1 -1
- package/dashboard/dist/assets/{namespaces-TG1aIpo_.js → namespaces-C3WtdO_9.js} +2 -2
- package/dashboard/dist/assets/{namespaces-TG1aIpo_.js.map → namespaces-C3WtdO_9.js.map} +1 -1
- package/dashboard/dist/assets/{roles-DhhLTvXg.js → roles-BDAsPpZG.js} +2 -2
- package/dashboard/dist/assets/{roles-DhhLTvXg.js.map → roles-BDAsPpZG.js.map} +1 -1
- package/dashboard/dist/assets/{settings-D9MBzEeB.js → settings-Ife_UwAp.js} +2 -2
- package/dashboard/dist/assets/{settings-D9MBzEeB.js.map → settings-Ife_UwAp.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-BxmcZoev.js → tasks-BquNDHDI.js} +2 -2
- package/dashboard/dist/assets/{tasks-BxmcZoev.js.map → tasks-BquNDHDI.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-BylecvvI.js → useEventHooks-anv_B2Yy.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-BylecvvI.js.map → useEventHooks-anv_B2Yy.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-ocmj11e_.js → useYamlActivityEvents-DN-PTgVx.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-ocmj11e_.js.map → useYamlActivityEvents-DN-PTgVx.js.map} +1 -1
- package/dashboard/dist/assets/{users-Ce5r-JAv.js → users-CFcxB4v6.js} +2 -2
- package/dashboard/dist/assets/{users-Ce5r-JAv.js.map → users-CFcxB4v6.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-D1DdudfH.js → vendor-icons-T4r2DSPD.js} +2 -2
- package/dashboard/dist/assets/{vendor-icons-D1DdudfH.js.map → vendor-icons-T4r2DSPD.js.map} +1 -1
- package/dashboard/dist/assets/{workflows-ykIeVbRJ.js → workflows-CeRci9z3.js} +2 -2
- package/dashboard/dist/assets/{workflows-ykIeVbRJ.js.map → workflows-CeRci9z3.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-WypmKYht.js → yaml-workflows-DLwd2BOX.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-WypmKYht.js.map → yaml-workflows-DLwd2BOX.js.map} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/docs/api/http/escalations.md +99 -0
- package/docs/api/http/tasks.md +47 -0
- package/docs/api/sdk/escalations.md +137 -0
- package/docs/api/sdk/tasks.md +40 -1
- package/package.json +1 -1
- package/dashboard/dist/assets/WorkflowPill-CP84Vqeg.js +0 -2
- package/dashboard/dist/assets/WorkflowPill-CP84Vqeg.js.map +0 -1
- package/dashboard/dist/assets/WorkflowsDashboard-QrvVFxtQ.js +0 -2
- package/dashboard/dist/assets/WorkflowsDashboard-QrvVFxtQ.js.map +0 -1
- package/dashboard/dist/assets/index-BUVQ6wmy.js +0 -6
- package/dashboard/dist/assets/index-BUVQ6wmy.js.map +0 -1
- package/dashboard/dist/assets/index-DHgnkykj.js.map +0 -1
- package/dashboard/dist/assets/index-DnmZbNxk.js.map +0 -1
- package/dashboard/dist/assets/index-n7td8zgX.js +0 -17
- package/dashboard/dist/assets/index-n7td8zgX.js.map +0 -1
package/build/api/escalations.js
CHANGED
|
@@ -664,7 +664,42 @@ async function resolveEscalation(input, auth) {
|
|
|
664
664
|
if (escalation.status !== 'pending') {
|
|
665
665
|
return { status: 409, error: 'Escalation not available for resolution' };
|
|
666
666
|
}
|
|
667
|
-
// 2.
|
|
667
|
+
// 2. Lightweight signal path: metadata.signal_id + escalation fields
|
|
668
|
+
// The workflow called `await conditionLT(signalId)` and created its
|
|
669
|
+
// own escalation with the signal_id in metadata. On resolution, we
|
|
670
|
+
// inject $escalation_id into the payload and signal the running
|
|
671
|
+
// workflow. The workflow is responsible for resolving the escalation
|
|
672
|
+
// (conditionLT handles this automatically via a durable activity).
|
|
673
|
+
const metadataSignalId = escalation.metadata?.signal_id;
|
|
674
|
+
if (metadataSignalId && escalation.workflow_id && escalation.task_queue && escalation.workflow_type) {
|
|
675
|
+
const client = (0, workers_1.createClient)();
|
|
676
|
+
const handle = await client.workflow.getHandle(escalation.task_queue, escalation.workflow_type, escalation.workflow_id);
|
|
677
|
+
await handle.signal(metadataSignalId, {
|
|
678
|
+
...resolverPayload,
|
|
679
|
+
$escalation_id: escalation.id,
|
|
680
|
+
});
|
|
681
|
+
(0, publish_1.publishEscalationEvent)({
|
|
682
|
+
type: 'escalation.resolved',
|
|
683
|
+
source: 'api',
|
|
684
|
+
workflowId: escalation.workflow_id,
|
|
685
|
+
workflowName: escalation.workflow_type,
|
|
686
|
+
taskQueue: escalation.task_queue,
|
|
687
|
+
taskId: escalation.task_id,
|
|
688
|
+
escalationId: escalation.id,
|
|
689
|
+
originId: escalation.origin_id ?? undefined,
|
|
690
|
+
status: 'resolved',
|
|
691
|
+
});
|
|
692
|
+
return {
|
|
693
|
+
status: 200,
|
|
694
|
+
data: {
|
|
695
|
+
signaled: true,
|
|
696
|
+
escalationId: escalation.id,
|
|
697
|
+
workflowId: escalation.workflow_id,
|
|
698
|
+
},
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
// 3. waitFor signal escalation -- signal the paused workflow directly
|
|
702
|
+
// (full signal_routing object from interceptor/MCP tool)
|
|
668
703
|
const signalRouting = escalation.metadata?.signal_routing;
|
|
669
704
|
if (signalRouting?.signalId) {
|
|
670
705
|
// Replace password fields with ephemeral tokens so plaintext never enters the signal store
|
|
@@ -716,7 +751,7 @@ async function resolveEscalation(input, auth) {
|
|
|
716
751
|
},
|
|
717
752
|
};
|
|
718
753
|
}
|
|
719
|
-
//
|
|
754
|
+
// 4. Reconstruct the original envelope from the escalation or task
|
|
720
755
|
let envelope = {};
|
|
721
756
|
if (escalation.envelope) {
|
|
722
757
|
try {
|
|
@@ -733,7 +768,7 @@ async function resolveEscalation(input, auth) {
|
|
|
733
768
|
catch { /* use empty */ }
|
|
734
769
|
}
|
|
735
770
|
}
|
|
736
|
-
//
|
|
771
|
+
// 5. Check escalation strategy for triage routing
|
|
737
772
|
const strategy = escalation_strategy_1.escalationStrategyRegistry.current;
|
|
738
773
|
if (strategy) {
|
|
739
774
|
const directive = await strategy.onResolution({
|
|
@@ -793,12 +828,12 @@ async function resolveEscalation(input, auth) {
|
|
|
793
828
|
};
|
|
794
829
|
}
|
|
795
830
|
}
|
|
796
|
-
//
|
|
831
|
+
// 6. If no workflow_type, this is a notification-only escalation -- acknowledge and close
|
|
797
832
|
if (!escalation.workflow_type || !escalation.task_queue) {
|
|
798
833
|
await escalationService.resolveEscalation(escalation.id, resolverPayload);
|
|
799
834
|
return { status: 200, data: { acknowledged: true, escalationId: escalation.id } };
|
|
800
835
|
}
|
|
801
|
-
//
|
|
836
|
+
// 7. Standard re-run: inject resolver data and start original workflow
|
|
802
837
|
envelope.resolver = resolverPayload;
|
|
803
838
|
envelope.lt = {
|
|
804
839
|
...envelope.lt,
|
package/build/api/tasks.d.ts
CHANGED
|
@@ -1,4 +1,28 @@
|
|
|
1
|
-
import type { LTApiResult } from '../types/sdk';
|
|
1
|
+
import type { LTApiResult, LTApiAuth } from '../types/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Create a task record.
|
|
4
|
+
*
|
|
5
|
+
* Tasks represent workflow executions tracked by the LT interceptor.
|
|
6
|
+
* Required fields: `workflow_id`, `workflow_type`, `lt_type`,
|
|
7
|
+
* `signal_id`, `parent_workflow_id`, and `envelope`.
|
|
8
|
+
*
|
|
9
|
+
* @returns `{ status: 201, data: <task record> }`
|
|
10
|
+
*/
|
|
11
|
+
export declare function createTask(input: {
|
|
12
|
+
workflow_id: string;
|
|
13
|
+
workflow_type: string;
|
|
14
|
+
lt_type: string;
|
|
15
|
+
task_queue?: string;
|
|
16
|
+
signal_id: string;
|
|
17
|
+
parent_workflow_id: string;
|
|
18
|
+
origin_id?: string;
|
|
19
|
+
parent_id?: string;
|
|
20
|
+
envelope?: string;
|
|
21
|
+
metadata?: Record<string, any>;
|
|
22
|
+
priority?: number;
|
|
23
|
+
trace_id?: string;
|
|
24
|
+
span_id?: string;
|
|
25
|
+
}, auth: LTApiAuth): Promise<LTApiResult>;
|
|
2
26
|
/**
|
|
3
27
|
* List tasks with optional filters.
|
|
4
28
|
*
|
package/build/api/tasks.js
CHANGED
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.createTask = createTask;
|
|
36
37
|
exports.listTasks = listTasks;
|
|
37
38
|
exports.getProcessStats = getProcessStats;
|
|
38
39
|
exports.listProcesses = listProcesses;
|
|
@@ -40,6 +41,54 @@ exports.getProcess = getProcess;
|
|
|
40
41
|
exports.getTask = getTask;
|
|
41
42
|
const taskService = __importStar(require("../services/task"));
|
|
42
43
|
const escalationService = __importStar(require("../services/escalation"));
|
|
44
|
+
/**
|
|
45
|
+
* Create a task record.
|
|
46
|
+
*
|
|
47
|
+
* Tasks represent workflow executions tracked by the LT interceptor.
|
|
48
|
+
* Required fields: `workflow_id`, `workflow_type`, `lt_type`,
|
|
49
|
+
* `signal_id`, `parent_workflow_id`, and `envelope`.
|
|
50
|
+
*
|
|
51
|
+
* @returns `{ status: 201, data: <task record> }`
|
|
52
|
+
*/
|
|
53
|
+
async function createTask(input, auth) {
|
|
54
|
+
try {
|
|
55
|
+
const { workflow_id, workflow_type, lt_type, signal_id, parent_workflow_id } = input;
|
|
56
|
+
if (!workflow_id || typeof workflow_id !== 'string') {
|
|
57
|
+
return { status: 400, error: 'workflow_id is required' };
|
|
58
|
+
}
|
|
59
|
+
if (!workflow_type || typeof workflow_type !== 'string') {
|
|
60
|
+
return { status: 400, error: 'workflow_type is required' };
|
|
61
|
+
}
|
|
62
|
+
if (!lt_type || typeof lt_type !== 'string') {
|
|
63
|
+
return { status: 400, error: 'lt_type is required' };
|
|
64
|
+
}
|
|
65
|
+
if (!signal_id || typeof signal_id !== 'string') {
|
|
66
|
+
return { status: 400, error: 'signal_id is required' };
|
|
67
|
+
}
|
|
68
|
+
if (!parent_workflow_id || typeof parent_workflow_id !== 'string') {
|
|
69
|
+
return { status: 400, error: 'parent_workflow_id is required' };
|
|
70
|
+
}
|
|
71
|
+
const task = await taskService.createTask({
|
|
72
|
+
workflow_id,
|
|
73
|
+
workflow_type,
|
|
74
|
+
lt_type,
|
|
75
|
+
task_queue: input.task_queue,
|
|
76
|
+
signal_id,
|
|
77
|
+
parent_workflow_id,
|
|
78
|
+
origin_id: input.origin_id,
|
|
79
|
+
parent_id: input.parent_id,
|
|
80
|
+
envelope: input.envelope ?? '{}',
|
|
81
|
+
metadata: input.metadata,
|
|
82
|
+
priority: input.priority,
|
|
83
|
+
trace_id: input.trace_id,
|
|
84
|
+
span_id: input.span_id,
|
|
85
|
+
});
|
|
86
|
+
return { status: 201, data: task };
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
return { status: 500, error: err.message };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
43
92
|
/**
|
|
44
93
|
* List tasks with optional filters.
|
|
45
94
|
*
|
package/build/api/workflows.js
CHANGED
|
@@ -72,7 +72,7 @@ function isResolveError(err) {
|
|
|
72
72
|
*/
|
|
73
73
|
async function invokeWorkflow(input, auth) {
|
|
74
74
|
try {
|
|
75
|
-
await (0, workflow_invocation_1.checkInvocationRoles)(input.type, auth.userId);
|
|
75
|
+
await (0, workflow_invocation_1.checkInvocationRoles)(input.type, auth.userId, auth.role);
|
|
76
76
|
const result = await (0, workflow_invocation_1.invokeWorkflow)({
|
|
77
77
|
workflowType: input.type,
|
|
78
78
|
data: input.data || {},
|
|
@@ -81,6 +81,8 @@ async function invokeWorkflow(input, auth) {
|
|
|
81
81
|
options: input.options,
|
|
82
82
|
auth: {
|
|
83
83
|
userId: auth.userId,
|
|
84
|
+
role: auth.role,
|
|
85
|
+
scopes: auth.scopes,
|
|
84
86
|
},
|
|
85
87
|
});
|
|
86
88
|
return {
|
|
@@ -260,9 +262,14 @@ async function listDiscoveredWorkflows(input) {
|
|
|
260
262
|
.map((workflowType) => {
|
|
261
263
|
const config = configMap.get(workflowType);
|
|
262
264
|
const worker = activeWorkers.get(workflowType);
|
|
265
|
+
const hasCertification = !!(config &&
|
|
266
|
+
((config.roles?.length ?? 0) > 0 ||
|
|
267
|
+
(config.consumes?.length ?? 0) > 0));
|
|
268
|
+
const tier = !config ? 'durable' : hasCertification ? 'certified' : 'configured';
|
|
263
269
|
return {
|
|
264
270
|
workflow_type: workflowType,
|
|
265
271
|
task_queue: config?.task_queue ?? worker?.taskQueue ?? null,
|
|
272
|
+
tier,
|
|
266
273
|
registered: !!config,
|
|
267
274
|
active: !!worker,
|
|
268
275
|
invocable: config?.invocable ?? !!worker,
|
package/build/examples/seed.js
CHANGED
|
@@ -137,6 +137,24 @@ const SEED_ENVELOPES = [
|
|
|
137
137
|
},
|
|
138
138
|
},
|
|
139
139
|
},
|
|
140
|
+
// -- Process 6: Basic Signal
|
|
141
|
+
{
|
|
142
|
+
label: 'Process 6 — Basic Signal',
|
|
143
|
+
workflowName: 'basicSignal',
|
|
144
|
+
taskQueue: 'long-tail-examples',
|
|
145
|
+
envelope: {
|
|
146
|
+
data: {
|
|
147
|
+
message: 'Seed deployment needs approval before proceeding.',
|
|
148
|
+
role: 'reviewer',
|
|
149
|
+
},
|
|
150
|
+
metadata: {
|
|
151
|
+
certified: false,
|
|
152
|
+
source: 'seed',
|
|
153
|
+
process: 'basic-signal',
|
|
154
|
+
description: 'Lightweight signal-based escalation — workflow stays running, no interceptor. Claim the escalation, fill the form, and resolve to resume the workflow.',
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
},
|
|
140
158
|
];
|
|
141
159
|
// Escalation chains: reviewer -> admin -> engineer (and cross-links)
|
|
142
160
|
const SEED_CHAINS = [
|
|
@@ -24,6 +24,13 @@ export interface BasicEchoEnvelopeData {
|
|
|
24
24
|
/** Duration to sleep before echoing (seconds). */
|
|
25
25
|
sleepSeconds?: number;
|
|
26
26
|
}
|
|
27
|
+
/** Basic signal — lightweight escalation via conditionLT. */
|
|
28
|
+
export interface BasicSignalEnvelopeData {
|
|
29
|
+
/** Message shown to the reviewer in the escalation description. */
|
|
30
|
+
message?: string;
|
|
31
|
+
/** Role to assign the escalation to. */
|
|
32
|
+
role?: string;
|
|
33
|
+
}
|
|
27
34
|
/** Assembly line — durable orchestrator with sequential human task queues. */
|
|
28
35
|
export interface AssemblyLineEnvelopeData {
|
|
29
36
|
/** Product name for the assembly run. */
|
|
@@ -53,6 +60,7 @@ export type WorkflowEnvelopeMap = {
|
|
|
53
60
|
reviewContent: ReviewContentEnvelopeData;
|
|
54
61
|
kitchenSink: KitchenSinkEnvelopeData;
|
|
55
62
|
basicEcho: BasicEchoEnvelopeData;
|
|
63
|
+
basicSignal: BasicSignalEnvelopeData;
|
|
56
64
|
assemblyLine: AssemblyLineEnvelopeData;
|
|
57
65
|
stepIterator: StepIteratorEnvelopeData;
|
|
58
66
|
reverter: ReverterEnvelopeData;
|
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
* Resolver types define the payload shape for resolving escalations.
|
|
6
6
|
* Per-workflow types are re-exported for convenience.
|
|
7
7
|
*/
|
|
8
|
-
export type { ReviewContentEnvelopeData, KitchenSinkEnvelopeData, BasicEchoEnvelopeData, AssemblyLineEnvelopeData, StepIteratorEnvelopeData, ReverterEnvelopeData, WorkflowEnvelopeMap, InvocableWorkflowType, } from './envelopes';
|
|
8
|
+
export type { ReviewContentEnvelopeData, KitchenSinkEnvelopeData, BasicEchoEnvelopeData, BasicSignalEnvelopeData, AssemblyLineEnvelopeData, StepIteratorEnvelopeData, ReverterEnvelopeData, WorkflowEnvelopeMap, InvocableWorkflowType, } from './envelopes';
|
|
9
9
|
export type { ResolverLTBlock, BaseResolverPayload, ReviewContentResolverPayload, } from './resolvers';
|
|
10
10
|
export type { ReviewContentInput, ReviewAnalysis, ReviewContentReturnData, ReviewContentReturn, ReviewContentEscalationData, ReviewContentEscalation, } from '../workflows/review-content/types';
|
|
@@ -41,6 +41,7 @@ const assemblyLineWorkflow = __importStar(require("./workflows/assembly-line"));
|
|
|
41
41
|
const workstationWorkflow = __importStar(require("./workflows/assembly-line/worker"));
|
|
42
42
|
const stepIteratorWorkflow = __importStar(require("./workflows/assembly-line/iterator"));
|
|
43
43
|
const reverterWorkflow = __importStar(require("./workflows/assembly-line/reverter"));
|
|
44
|
+
const basicSignalWorkflow = __importStar(require("./workflows/basic-signal"));
|
|
44
45
|
/**
|
|
45
46
|
* Example workers that ship with Long Tail.
|
|
46
47
|
* Pass these to `start({ workers: [...exampleWorkers] })` or enable
|
|
@@ -54,4 +55,5 @@ exports.exampleWorkers = [
|
|
|
54
55
|
{ taskQueue: 'long-tail-examples', workflow: workstationWorkflow.workstation },
|
|
55
56
|
{ taskQueue: 'long-tail-examples', workflow: stepIteratorWorkflow.stepIterator },
|
|
56
57
|
{ taskQueue: 'long-tail-examples', workflow: reverterWorkflow.reverter },
|
|
58
|
+
{ taskQueue: 'long-tail-examples', workflow: basicSignalWorkflow.basicSignal },
|
|
57
59
|
];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Basic Signal Activities
|
|
3
|
+
*
|
|
4
|
+
* Simple activity for post-resolution processing. The escalation
|
|
5
|
+
* creation and resolution are handled via interceptor activities
|
|
6
|
+
* (ltCreateEscalation / ltResolveEscalation) proxied from the workflow.
|
|
7
|
+
*/
|
|
8
|
+
export declare function processApproval(input: {
|
|
9
|
+
approved: boolean;
|
|
10
|
+
notes: string;
|
|
11
|
+
message: string;
|
|
12
|
+
}): Promise<{
|
|
13
|
+
message: string;
|
|
14
|
+
approved: boolean;
|
|
15
|
+
notes: string;
|
|
16
|
+
processedAt: string;
|
|
17
|
+
}>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Basic Signal Activities
|
|
4
|
+
*
|
|
5
|
+
* Simple activity for post-resolution processing. The escalation
|
|
6
|
+
* creation and resolution are handled via interceptor activities
|
|
7
|
+
* (ltCreateEscalation / ltResolveEscalation) proxied from the workflow.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.processApproval = processApproval;
|
|
11
|
+
async function processApproval(input) {
|
|
12
|
+
return {
|
|
13
|
+
message: input.message,
|
|
14
|
+
approved: input.approved,
|
|
15
|
+
notes: input.notes,
|
|
16
|
+
processedAt: new Date().toISOString(),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Basic Signal Workflow
|
|
3
|
+
*
|
|
4
|
+
* Lightweight signal-based escalation — the workflow stays running
|
|
5
|
+
* while waiting for human input. No interceptor, no certification.
|
|
6
|
+
*
|
|
7
|
+
* 1. Creates an escalation with `signal_id` in metadata
|
|
8
|
+
* 2. Pauses via `conditionLT(signalId)` — workflow stays alive
|
|
9
|
+
* 3. Dashboard resolver signals in with the form payload
|
|
10
|
+
* 4. `conditionLT` resolves the escalation via durable activity
|
|
11
|
+
* 5. Workflow continues with the clean resolver payload
|
|
12
|
+
*
|
|
13
|
+
* This demonstrates the lightweight alternative to the certified
|
|
14
|
+
* interceptor pattern — same escalation UX, simpler wiring.
|
|
15
|
+
*/
|
|
16
|
+
import type { LTEnvelope } from '../../../types';
|
|
17
|
+
export declare function basicSignal(envelope: LTEnvelope): Promise<any>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Basic Signal Workflow
|
|
4
|
+
*
|
|
5
|
+
* Lightweight signal-based escalation — the workflow stays running
|
|
6
|
+
* while waiting for human input. No interceptor, no certification.
|
|
7
|
+
*
|
|
8
|
+
* 1. Creates an escalation with `signal_id` in metadata
|
|
9
|
+
* 2. Pauses via `conditionLT(signalId)` — workflow stays alive
|
|
10
|
+
* 3. Dashboard resolver signals in with the form payload
|
|
11
|
+
* 4. `conditionLT` resolves the escalation via durable activity
|
|
12
|
+
* 5. Workflow continues with the clean resolver payload
|
|
13
|
+
*
|
|
14
|
+
* This demonstrates the lightweight alternative to the certified
|
|
15
|
+
* interceptor pattern — same escalation UX, simpler wiring.
|
|
16
|
+
*/
|
|
17
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
+
}
|
|
23
|
+
Object.defineProperty(o, k2, desc);
|
|
24
|
+
}) : (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
o[k2] = m[k];
|
|
27
|
+
}));
|
|
28
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
+
}) : function(o, v) {
|
|
31
|
+
o["default"] = v;
|
|
32
|
+
});
|
|
33
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
+
var ownKeys = function(o) {
|
|
35
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
+
var ar = [];
|
|
37
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
+
return ar;
|
|
39
|
+
};
|
|
40
|
+
return ownKeys(o);
|
|
41
|
+
};
|
|
42
|
+
return function (mod) {
|
|
43
|
+
if (mod && mod.__esModule) return mod;
|
|
44
|
+
var result = {};
|
|
45
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
+
__setModuleDefault(result, mod);
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
})();
|
|
50
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
+
exports.basicSignal = basicSignal;
|
|
52
|
+
const hotmesh_1 = require("@hotmeshio/hotmesh");
|
|
53
|
+
const condition_1 = require("../../../services/orchestrator/condition");
|
|
54
|
+
const interceptorActivities = __importStar(require("../../../services/interceptor/activities"));
|
|
55
|
+
const activities = __importStar(require("./activities"));
|
|
56
|
+
const LT_ACTIVITY_QUEUE = 'lt-interceptor';
|
|
57
|
+
async function basicSignal(envelope) {
|
|
58
|
+
const { message = 'Please review and approve.', role = 'reviewer' } = envelope.data;
|
|
59
|
+
const { ltCreateEscalation } = hotmesh_1.Durable.workflow.proxyActivities({
|
|
60
|
+
activities: interceptorActivities,
|
|
61
|
+
taskQueue: LT_ACTIVITY_QUEUE,
|
|
62
|
+
retry: { maximumAttempts: 3 },
|
|
63
|
+
});
|
|
64
|
+
const { processApproval } = hotmesh_1.Durable.workflow.proxyActivities({
|
|
65
|
+
activities,
|
|
66
|
+
});
|
|
67
|
+
const ctx = hotmesh_1.Durable.workflow.workflowInfo();
|
|
68
|
+
const signalId = `approval-${ctx.workflowId}`;
|
|
69
|
+
// Create escalation with signal_id — dashboard knows to signal, not re-run.
|
|
70
|
+
//
|
|
71
|
+
// The resolver_schema registered in the workflow config provides the
|
|
72
|
+
// default form. To override per-instance, pass metadata.form_schema:
|
|
73
|
+
//
|
|
74
|
+
// metadata: {
|
|
75
|
+
// signal_id: signalId,
|
|
76
|
+
// form_schema: {
|
|
77
|
+
// properties: {
|
|
78
|
+
// approved: { type: 'boolean', default: false, description: 'Approve?' },
|
|
79
|
+
// notes: { type: 'string', default: '', description: 'Reviewer notes' },
|
|
80
|
+
// environment: { type: 'string', enum: ['staging', 'production'] },
|
|
81
|
+
// api_key: { type: 'string', format: 'password', description: 'Deploy key (ephemeral)' },
|
|
82
|
+
// confidence: { type: 'number', default: 0, description: 'Confidence 0-1' },
|
|
83
|
+
// },
|
|
84
|
+
// },
|
|
85
|
+
// },
|
|
86
|
+
//
|
|
87
|
+
// When form_schema is present it overrides the workflow config's
|
|
88
|
+
// resolver_schema for this specific escalation instance.
|
|
89
|
+
await ltCreateEscalation({
|
|
90
|
+
type: 'signal-approval',
|
|
91
|
+
subtype: 'basic-signal',
|
|
92
|
+
description: message,
|
|
93
|
+
role,
|
|
94
|
+
envelope: JSON.stringify(envelope),
|
|
95
|
+
workflowId: ctx.workflowId,
|
|
96
|
+
workflowType: 'basicSignal',
|
|
97
|
+
taskQueue: ctx.taskQueue,
|
|
98
|
+
metadata: {
|
|
99
|
+
signal_id: signalId,
|
|
100
|
+
// No form_schema here — the workflow config's resolver_schema is used.
|
|
101
|
+
// Pass form_schema to override per-instance (see comment above).
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
// Pause — conditionLT handles $escalation_id stripping and resolution
|
|
105
|
+
const decision = await (0, condition_1.conditionLT)(signalId);
|
|
106
|
+
// Continue with the clean resolver payload
|
|
107
|
+
const result = await processApproval({
|
|
108
|
+
approved: decision.approved,
|
|
109
|
+
notes: decision.notes || '',
|
|
110
|
+
message,
|
|
111
|
+
});
|
|
112
|
+
return {
|
|
113
|
+
type: 'return',
|
|
114
|
+
data: result,
|
|
115
|
+
};
|
|
116
|
+
}
|
package/build/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { start } from './start';
|
|
|
2
2
|
export { registerLT, createLTInterceptor } from './services/interceptor';
|
|
3
3
|
export { createLTActivityInterceptor } from './services/interceptor/activity-interceptor';
|
|
4
4
|
export { executeLT } from './services/orchestrator';
|
|
5
|
+
export { conditionLT } from './services/orchestrator/condition';
|
|
5
6
|
export type { ExecuteLTOptions } from './services/orchestrator/types';
|
|
6
7
|
export { JwtAuthAdapter, createAuthMiddleware, requireAuth, requireAdmin, signToken } from './modules/auth';
|
|
7
8
|
export * from './types';
|
package/build/index.js
CHANGED
|
@@ -36,7 +36,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
36
36
|
};
|
|
37
37
|
})();
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.
|
|
39
|
+
exports.createClient = exports.CallbackEventAdapter = exports.seedSystemMcpServers = exports.builtinMcpServerFactories = exports.getSystemWorkers = exports.registerMcpTool = exports.getToolContext = exports.getActivityIdentity = exports.seedExamples = exports.exampleWorkers = exports.McpEscalationStrategy = exports.DefaultEscalationStrategy = exports.escalationStrategyRegistry = exports.McpVisionServer = exports.McpTranslationServer = exports.McpServer = exports.McpClient = exports.McpService = exports.BuiltInMcpAdapter = exports.mcpRegistry = exports.defaultMaintenanceConfig = exports.maintenanceRegistry = exports.PinoLoggerAdapter = exports.loggerRegistry = exports.HoneycombTelemetryAdapter = exports.telemetryRegistry = exports.publishWorkflowEvent = exports.publishEscalationEvent = exports.publishTaskEvent = exports.publishMilestoneEvent = exports.SocketIOEventAdapter = exports.InMemoryEventAdapter = exports.NatsEventAdapter = exports.eventRegistry = exports.ltConfig = exports.UserService = exports.ConfigService = exports.EscalationService = exports.TaskService = exports.signToken = exports.requireAdmin = exports.requireAuth = exports.createAuthMiddleware = exports.JwtAuthAdapter = exports.conditionLT = exports.executeLT = exports.createLTActivityInterceptor = exports.createLTInterceptor = exports.registerLT = exports.start = void 0;
|
|
40
|
+
exports.api = void 0;
|
|
40
41
|
const config_1 = require("./modules/config");
|
|
41
42
|
const logger_1 = require("./lib/logger");
|
|
42
43
|
const start_1 = require("./start");
|
|
@@ -50,6 +51,8 @@ var activity_interceptor_1 = require("./services/interceptor/activity-intercepto
|
|
|
50
51
|
Object.defineProperty(exports, "createLTActivityInterceptor", { enumerable: true, get: function () { return activity_interceptor_1.createLTActivityInterceptor; } });
|
|
51
52
|
var orchestrator_1 = require("./services/orchestrator");
|
|
52
53
|
Object.defineProperty(exports, "executeLT", { enumerable: true, get: function () { return orchestrator_1.executeLT; } });
|
|
54
|
+
var condition_1 = require("./services/orchestrator/condition");
|
|
55
|
+
Object.defineProperty(exports, "conditionLT", { enumerable: true, get: function () { return condition_1.conditionLT; } });
|
|
53
56
|
var auth_1 = require("./modules/auth");
|
|
54
57
|
Object.defineProperty(exports, "JwtAuthAdapter", { enumerable: true, get: function () { return auth_1.JwtAuthAdapter; } });
|
|
55
58
|
Object.defineProperty(exports, "createAuthMiddleware", { enumerable: true, get: function () { return auth_1.createAuthMiddleware; } });
|
|
@@ -55,7 +55,14 @@ VALUES
|
|
|
55
55
|
'Kitchen sink — demonstrates sleep, signals, parallel activities, escalation, and every durable primitive',
|
|
56
56
|
'{}',
|
|
57
57
|
'{"data": {"name": "World", "mode": "full"}, "metadata": {"source": "dashboard"}}'::jsonb,
|
|
58
|
-
NULL)
|
|
58
|
+
NULL),
|
|
59
|
+
|
|
60
|
+
-- Basic signal (configured, NOT certified — no escalation roles)
|
|
61
|
+
('basicSignal', 'long-tail-examples', 'reviewer', true,
|
|
62
|
+
'Signal-based escalation — workflow stays running while waiting for human input via conditionLT',
|
|
63
|
+
'{}',
|
|
64
|
+
'{"data": {"message": "Deployment approval needed for v2.1.0", "role": "reviewer"}, "metadata": {"certified": false, "source": "dashboard"}}'::jsonb,
|
|
65
|
+
'{"properties": {"approved": {"type": "boolean", "default": false, "description": "Approve this deployment?"}, "notes": {"type": "string", "default": "", "description": "Reviewer notes — visible to the workflow author"}}}'::jsonb)
|
|
59
66
|
ON CONFLICT (workflow_type) DO NOTHING;
|
|
60
67
|
|
|
61
68
|
-- ─── Assign roles to all workflows ──────────────────────────────────────────
|
|
@@ -63,5 +70,6 @@ ON CONFLICT (workflow_type) DO NOTHING;
|
|
|
63
70
|
INSERT INTO lt_config_roles (workflow_type, role)
|
|
64
71
|
SELECT workflow_type, unnest(ARRAY['reviewer', 'engineer', 'admin'])
|
|
65
72
|
FROM lt_config_workflows
|
|
73
|
+
WHERE workflow_type != 'basicSignal'
|
|
66
74
|
ON CONFLICT (workflow_type, role) DO NOTHING;
|
|
67
75
|
|
|
@@ -14,7 +14,14 @@ declare class LTConfigCache {
|
|
|
14
14
|
getProviderData(name: string, originId: string): Promise<LTProviderData>;
|
|
15
15
|
/** Force cache reload on next access. Call after config mutations. */
|
|
16
16
|
invalidate(): void;
|
|
17
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Get the resolved config for a workflow, but only if certified.
|
|
19
|
+
*
|
|
20
|
+
* The interceptor uses this to decide whether to wrap the workflow
|
|
21
|
+
* with task tracking, escalation handling, and re-run detection.
|
|
22
|
+
* Configured-but-not-certified workflows (no roles, no consumes)
|
|
23
|
+
* return null so the interceptor skips them.
|
|
24
|
+
*/
|
|
18
25
|
getResolvedConfig(name: string): Promise<LTResolvedConfig | null>;
|
|
19
26
|
}
|
|
20
27
|
export declare const ltConfig: LTConfigCache;
|
|
@@ -101,10 +101,20 @@ class LTConfigCache {
|
|
|
101
101
|
this.loadedAt = 0;
|
|
102
102
|
this.loadPromise = null;
|
|
103
103
|
}
|
|
104
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* Get the resolved config for a workflow, but only if certified.
|
|
106
|
+
*
|
|
107
|
+
* The interceptor uses this to decide whether to wrap the workflow
|
|
108
|
+
* with task tracking, escalation handling, and re-run detection.
|
|
109
|
+
* Configured-but-not-certified workflows (no roles, no consumes)
|
|
110
|
+
* return null so the interceptor skips them.
|
|
111
|
+
*/
|
|
105
112
|
async getResolvedConfig(name) {
|
|
106
113
|
const config = await this.get(name);
|
|
107
|
-
|
|
114
|
+
if (!config)
|
|
115
|
+
return null;
|
|
116
|
+
const isCertified = (config.roles?.length ?? 0) > 0 || (config.consumes?.length ?? 0) > 0;
|
|
117
|
+
return isCertified ? config : null;
|
|
108
118
|
}
|
|
109
119
|
}
|
|
110
120
|
exports.ltConfig = new LTConfigCache();
|
package/build/routes/tasks.js
CHANGED
|
@@ -36,6 +36,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
const express_1 = require("express");
|
|
37
37
|
const api = __importStar(require("../api/tasks"));
|
|
38
38
|
const router = (0, express_1.Router)();
|
|
39
|
+
/**
|
|
40
|
+
* POST /api/tasks
|
|
41
|
+
* Create a new task record.
|
|
42
|
+
* Body: { workflow_id, workflow_type, lt_type, signal_id, parent_workflow_id, envelope, ... }
|
|
43
|
+
*/
|
|
44
|
+
router.post('/', async (req, res) => {
|
|
45
|
+
const result = await api.createTask({
|
|
46
|
+
workflow_id: req.body?.workflow_id,
|
|
47
|
+
workflow_type: req.body?.workflow_type,
|
|
48
|
+
lt_type: req.body?.lt_type,
|
|
49
|
+
task_queue: req.body?.task_queue,
|
|
50
|
+
signal_id: req.body?.signal_id,
|
|
51
|
+
parent_workflow_id: req.body?.parent_workflow_id,
|
|
52
|
+
origin_id: req.body?.origin_id,
|
|
53
|
+
parent_id: req.body?.parent_id,
|
|
54
|
+
envelope: req.body?.envelope,
|
|
55
|
+
metadata: req.body?.metadata,
|
|
56
|
+
priority: req.body?.priority,
|
|
57
|
+
trace_id: req.body?.trace_id,
|
|
58
|
+
span_id: req.body?.span_id,
|
|
59
|
+
}, { userId: req.auth?.userId ?? '', role: req.auth?.role, scopes: req.auth?.scopes });
|
|
60
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
61
|
+
});
|
|
39
62
|
/**
|
|
40
63
|
* GET /api/tasks
|
|
41
64
|
* List tasks with optional filters.
|
|
@@ -60,7 +60,7 @@ router.post('/:type/invoke', async (req, res) => {
|
|
|
60
60
|
metadata,
|
|
61
61
|
execute_as,
|
|
62
62
|
options: Object.keys(options).length > 0 ? options : undefined,
|
|
63
|
-
}, { userId: req.auth?.userId ?? '' });
|
|
63
|
+
}, { userId: req.auth?.userId ?? '', role: req.auth?.role, scopes: req.auth?.scopes });
|
|
64
64
|
res.status(result.status).json(result.data ?? { error: result.error });
|
|
65
65
|
});
|
|
66
66
|
// ── Workflow observation ────────────────────────────────────────────────────
|
package/build/sdk/index.d.ts
CHANGED
|
@@ -47,6 +47,21 @@ export interface LTClientOptions {
|
|
|
47
47
|
*/
|
|
48
48
|
export declare function createClient(options?: LTClientOptions): {
|
|
49
49
|
tasks: {
|
|
50
|
+
create: (input: {
|
|
51
|
+
workflow_id: string;
|
|
52
|
+
workflow_type: string;
|
|
53
|
+
lt_type: string;
|
|
54
|
+
task_queue?: string;
|
|
55
|
+
signal_id: string;
|
|
56
|
+
parent_workflow_id: string;
|
|
57
|
+
origin_id?: string;
|
|
58
|
+
parent_id?: string;
|
|
59
|
+
envelope?: string;
|
|
60
|
+
metadata?: Record<string, any>;
|
|
61
|
+
priority?: number;
|
|
62
|
+
trace_id?: string;
|
|
63
|
+
span_id?: string;
|
|
64
|
+
}, auth?: LTApiAuth) => Promise<LTApiResult<any>>;
|
|
50
65
|
list: typeof tasksApi.listTasks;
|
|
51
66
|
get: typeof tasksApi.getTask;
|
|
52
67
|
listProcesses: typeof tasksApi.listProcesses;
|
package/build/sdk/index.js
CHANGED
|
@@ -100,6 +100,7 @@ function createClient(options = {}) {
|
|
|
100
100
|
return {
|
|
101
101
|
// ── Tasks ──────────────────────────────────────────────────────────────
|
|
102
102
|
tasks: {
|
|
103
|
+
create: bindAuth(tasksApi.createTask, auth),
|
|
103
104
|
list: tasksApi.listTasks,
|
|
104
105
|
get: tasksApi.getTask,
|
|
105
106
|
listProcesses: tasksApi.listProcesses,
|
|
@@ -98,14 +98,20 @@ function createLTInterceptor(options) {
|
|
|
98
98
|
taskQueue: activityTaskQueue,
|
|
99
99
|
retry: { maximumAttempts: 3 },
|
|
100
100
|
});
|
|
101
|
-
|
|
101
|
+
const envelope = (0, state_1.extractEnvelope)(ctx);
|
|
102
|
+
// 2. Fast path: envelope.metadata.certified === false skips the DB
|
|
103
|
+
// lookup entirely. Use this for configured (non-certified) workflows
|
|
104
|
+
// that manage their own escalation lifecycle via conditionLT.
|
|
105
|
+
if (envelope?.metadata?.certified === false) {
|
|
106
|
+
const toolCtx = (0, envelope_1.buildToolContextFromEnvelope)(envelope, wf.workflowId, wf.workflowTrace, wf.workflowSpan);
|
|
107
|
+
return toolCtx ? (0, context_2.runWithToolContext)(toolCtx, next) : next();
|
|
108
|
+
}
|
|
109
|
+
// 3. Load config — unregistered/uncertified workflows get ToolContext only
|
|
102
110
|
const wfConfig = await activities.ltGetWorkflowConfig(wf.workflowName);
|
|
103
111
|
if (!wfConfig) {
|
|
104
|
-
const envelope = (0, state_1.extractEnvelope)(ctx);
|
|
105
112
|
const toolCtx = (0, envelope_1.buildToolContextFromEnvelope)(envelope, wf.workflowId, wf.workflowTrace, wf.workflowSpan);
|
|
106
113
|
return toolCtx ? (0, context_2.runWithToolContext)(toolCtx, next) : next();
|
|
107
114
|
}
|
|
108
|
-
const envelope = (0, state_1.extractEnvelope)(ctx);
|
|
109
115
|
const taskQueue = (0, lifecycle_1.deriveTaskQueue)(wf);
|
|
110
116
|
// 3. Find existing task and handle re-run escalation resolution
|
|
111
117
|
const existingTask = await activities.ltGetTaskByWorkflowId(wf.workflowId);
|