@hotmeshio/long-tail 0.5.11 → 0.6.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/README.md +1 -0
- package/build/api/diagnostics.d.ts +5 -0
- package/build/api/diagnostics.js +5 -1
- package/build/api/escalations/bulk.js +9 -1
- package/build/api/escalations/cancel.js +5 -7
- package/build/api/escalations/claim.js +18 -15
- package/build/api/escalations/create.d.ts +6 -0
- package/build/api/escalations/create.js +11 -8
- package/build/api/escalations/facets.d.ts +18 -0
- package/build/api/escalations/facets.js +115 -0
- package/build/api/escalations/helpers.d.ts +70 -1
- package/build/api/escalations/helpers.js +101 -7
- package/build/api/escalations/index.d.ts +3 -2
- package/build/api/escalations/index.js +7 -1
- package/build/api/escalations/list.d.ts +23 -2
- package/build/api/escalations/list.js +111 -10
- package/build/api/escalations/metadata.js +22 -27
- package/build/api/escalations/resolve.d.ts +19 -1
- package/build/api/escalations/resolve.js +111 -26
- package/build/api/escalations/single.js +8 -8
- package/build/api/settings.d.ts +1 -1
- package/build/api/settings.js +3 -1
- package/build/api/users.d.ts +6 -0
- package/build/api/users.js +29 -1
- package/build/api/workflows/invocation.d.ts +6 -0
- package/build/api/workflows/invocation.js +6 -2
- package/build/bin/ltc.js +40 -0
- package/build/lib/cli/commands/escalations.d.ts +36 -0
- package/build/lib/cli/commands/escalations.js +98 -0
- package/build/lib/db/schemas/001_schema.sql +10 -5
- package/build/lib/db/schemas/012_lt_tasks_workflow_id_unique.sql +20 -0
- package/build/lib/db/schemas/013_role_scope.sql +37 -0
- package/build/modules/features.d.ts +19 -0
- package/build/modules/features.js +16 -0
- package/build/modules/version.d.ts +10 -5
- package/build/modules/version.js +27 -11
- package/build/routes/diagnostics.js +15 -2
- package/build/routes/escalations/facets.d.ts +7 -0
- package/build/routes/escalations/facets.js +81 -0
- package/build/routes/escalations/index.js +3 -0
- package/build/routes/escalations/list.js +48 -0
- package/build/routes/escalations/resolve.js +22 -4
- package/build/routes/users.js +9 -5
- package/build/routes/workflows/invocation.js +12 -4
- package/build/sdk/index.d.ts +35 -2
- package/build/sdk/index.js +7 -0
- package/build/services/diagnostics/index.d.ts +40 -6
- package/build/services/diagnostics/index.js +54 -5
- package/build/services/escalation/crud.d.ts +56 -6
- package/build/services/escalation/crud.js +102 -31
- package/build/services/escalation/facet-sql.d.ts +18 -0
- package/build/services/escalation/facet-sql.js +118 -0
- package/build/services/escalation/facets.d.ts +45 -0
- package/build/services/escalation/facets.js +218 -0
- package/build/services/escalation/index.d.ts +1 -0
- package/build/services/escalation/index.js +8 -1
- package/build/services/escalation/queries.d.ts +47 -0
- package/build/services/escalation/queries.js +185 -2
- package/build/services/escalation/sql.d.ts +15 -2
- package/build/services/escalation/sql.js +80 -3
- package/build/services/interceptor/activities/escalation.d.ts +2 -0
- package/build/services/interceptor/activities/escalation.js +1 -1
- package/build/services/interceptor/lifecycle.js +4 -0
- package/build/services/mcp/server-tools.js +10 -4
- package/build/services/orchestrator/condition.js +6 -2
- package/build/services/role/index.js +2 -3
- package/build/services/role/sql.d.ts +8 -0
- package/build/services/role/sql.js +17 -1
- package/build/services/task/crud.js +22 -14
- package/build/services/task/process.js +3 -21
- package/build/services/task/resolve.d.ts +5 -3
- package/build/services/task/resolve.js +9 -6
- package/build/services/task/sql.d.ts +30 -2
- package/build/services/task/sql.js +72 -2
- package/build/services/user/crud.d.ts +1 -0
- package/build/services/user/crud.js +29 -11
- package/build/services/user/index.d.ts +2 -1
- package/build/services/user/index.js +12 -1
- package/build/services/user/rbac.d.ts +18 -0
- package/build/services/user/rbac.js +27 -0
- package/build/services/user/roles.d.ts +7 -2
- package/build/services/user/roles.js +21 -5
- package/build/services/user/scope.d.ts +22 -0
- package/build/services/user/scope.js +50 -0
- package/build/services/user/seed-admin.js +34 -17
- package/build/services/user/sql.d.ts +18 -7
- package/build/services/user/sql.js +38 -13
- package/build/services/user/sso-provision.js +41 -24
- package/build/services/user/types.d.ts +9 -5
- package/build/start/adapters.js +3 -0
- package/build/system/mcp-servers/admin/diagnostics.d.ts +5 -4
- package/build/system/mcp-servers/admin/diagnostics.js +12 -10
- package/build/system/mcp-servers/admin/escalations.d.ts +6 -0
- package/build/system/mcp-servers/admin/escalations.js +247 -54
- package/build/system/mcp-servers/admin/index.js +3 -3
- package/build/system/mcp-servers/admin/schemas.d.ts +417 -3
- package/build/system/mcp-servers/admin/schemas.js +101 -5
- package/build/system/mcp-servers/admin/users.js +28 -2
- package/build/system/mcp-servers/admin/workflows.js +23 -12
- package/build/system/seed/tool-manifests-admin.d.ts +1324 -562
- package/build/system/seed/tool-manifests-admin.js +10 -2
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/envelope.d.ts +7 -0
- package/build/types/facets.d.ts +60 -0
- package/build/types/facets.js +10 -0
- package/build/types/index.d.ts +2 -1
- package/build/types/startup.d.ts +9 -0
- package/build/types/user.d.ts +11 -0
- package/dashboard/dist/assets/AdminDashboard-2CZ8py9X.js +2 -0
- package/dashboard/dist/assets/{AdminDashboard-DZpduYdW.js.map → AdminDashboard-2CZ8py9X.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-SFnHMIP6.js → AgentConfigPage-D68sodgo.js} +7 -7
- package/dashboard/dist/assets/{AgentConfigPage-SFnHMIP6.js.map → AgentConfigPage-D68sodgo.js.map} +1 -1
- package/dashboard/dist/assets/AgentDetailPage-BmhuWbKi.js +4 -0
- package/dashboard/dist/assets/AgentDetailPage-BmhuWbKi.js.map +1 -0
- package/dashboard/dist/assets/AgentsPage-C4SKQVeU.js +2 -0
- package/dashboard/dist/assets/AgentsPage-C4SKQVeU.js.map +1 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-9RBEYwkt.js +2 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-9RBEYwkt.js.map +1 -0
- package/dashboard/dist/assets/{BotPicker-Dse2jW4b.js → BotPicker-D-FvXJOM.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-Dse2jW4b.js.map → BotPicker-D-FvXJOM.js.map} +1 -1
- package/dashboard/dist/assets/CapabilitiesPage-ByDf6WJr.js +2 -0
- package/dashboard/dist/assets/{CapabilitiesPage-DTfKCzBQ.js.map → CapabilitiesPage-ByDf6WJr.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-8vf38J6K.js → CollapsibleSection-BjGNYEvh.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-8vf38J6K.js.map → CollapsibleSection-BjGNYEvh.js.map} +1 -1
- package/dashboard/dist/assets/CopyableId-blg-gZvT.js +2 -0
- package/dashboard/dist/assets/CopyableId-blg-gZvT.js.map +1 -0
- package/dashboard/dist/assets/{CredentialsPage-7C4M-hrH.js → CredentialsPage-DvCA-wQN.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-7C4M-hrH.js.map → CredentialsPage-DvCA-wQN.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-DrGWtaSY.js → CronLabel-DBMurd_c.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-DrGWtaSY.js.map → CronLabel-DBMurd_c.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-Vcmr4LiR.js → CustomDurationPicker-DHflFoEa.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-Vcmr4LiR.js.map → CustomDurationPicker-DHflFoEa.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-Dwpgbueb.js → DropZone-CUtdp99Z.js} +2 -2
- package/dashboard/dist/assets/{DropZone-Dwpgbueb.js.map → DropZone-CUtdp99Z.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-BNexhR5d.js → ElapsedCell-CSjcVOpo.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-BNexhR5d.js.map → ElapsedCell-CSjcVOpo.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-BI3DEwYP.js → EscalationsOverview-BUqRNJbK.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-BI3DEwYP.js.map → EscalationsOverview-BUqRNJbK.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-CwvX_L9t.js → EventTable-Chz-6XPE.js} +2 -2
- package/dashboard/dist/assets/{EventTable-CwvX_L9t.js.map → EventTable-Chz-6XPE.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-C-3b8WK0.js → GraphInvokePage-BXdgciWg.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-C-3b8WK0.js.map → GraphInvokePage-BXdgciWg.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-BS_-jcHr.js → HomePage-CEMxnk0r.js} +2 -2
- package/dashboard/dist/assets/{HomePage-BS_-jcHr.js.map → HomePage-CEMxnk0r.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-BH9rwQVE.js → ListToolbar-_73JCdbB.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-BH9rwQVE.js.map → ListToolbar-_73JCdbB.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-C9iOdE7E.js → McpOverview-DfdqxhSz.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-C9iOdE7E.js.map → McpOverview-DfdqxhSz.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-DMN-yqvJ.js → McpQueryDetailPage-DPAljieY.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-DMN-yqvJ.js.map → McpQueryDetailPage-DPAljieY.js.map} +1 -1
- package/dashboard/dist/assets/McpQueryPage-D5cSziYS.js +2 -0
- package/dashboard/dist/assets/McpQueryPage-D5cSziYS.js.map +1 -0
- package/dashboard/dist/assets/{McpRunDetailPage-Wb47sRvo.js → McpRunDetailPage-DwNb9wZg.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-Wb47sRvo.js.map → McpRunDetailPage-DwNb9wZg.js.map} +1 -1
- package/dashboard/dist/assets/McpRunsPage-O5H6yStl.js +2 -0
- package/dashboard/dist/assets/McpRunsPage-O5H6yStl.js.map +1 -0
- package/dashboard/dist/assets/{NamespacePill-DnJl4Lre.js → NamespacePill-uW-xOedj.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-DnJl4Lre.js.map → NamespacePill-uW-xOedj.js.map} +1 -1
- package/dashboard/dist/assets/OperatorDashboard-DYw9Ekv5.js +2 -0
- package/dashboard/dist/assets/OperatorDashboard-DYw9Ekv5.js.map +1 -0
- package/dashboard/dist/assets/PageHeader-DVOZjBfL.js +2 -0
- package/dashboard/dist/assets/PageHeader-DVOZjBfL.js.map +1 -0
- package/dashboard/dist/assets/{PageHeaderWithStats-BuKc9MKt.js → PageHeaderWithStats-DtTpDHOd.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-BuKc9MKt.js.map → PageHeaderWithStats-DtTpDHOd.js.map} +1 -1
- package/dashboard/dist/assets/PriorityBadge-B4ykBH7f.js +2 -0
- package/dashboard/dist/assets/PriorityBadge-B4ykBH7f.js.map +1 -0
- package/dashboard/dist/assets/{ProcessDetailPage-CvPx-h8y.js → ProcessDetailPage-B0Dokcx9.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-CvPx-h8y.js.map → ProcessDetailPage-B0Dokcx9.js.map} +1 -1
- package/dashboard/dist/assets/ProcessesListPage-Cc87WIjL.js +2 -0
- package/dashboard/dist/assets/ProcessesListPage-Cc87WIjL.js.map +1 -0
- package/dashboard/dist/assets/RolePill-BaW-30TC.js +2 -0
- package/dashboard/dist/assets/RolePill-BaW-30TC.js.map +1 -0
- package/dashboard/dist/assets/{RolesPage-W5ZjOHpg.js → RolesPage-cp6PiF08.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-W5ZjOHpg.js.map → RolesPage-cp6PiF08.js.map} +1 -1
- package/dashboard/dist/assets/RowActions-BA9L9djf.js +2 -0
- package/dashboard/dist/assets/RowActions-BA9L9djf.js.map +1 -0
- package/dashboard/dist/assets/{RunAsSelector-CvxGTNGT.js → RunAsSelector-2LWkjSnO.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-CvxGTNGT.js.map → RunAsSelector-2LWkjSnO.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-BWhFSr2d.js → StickyPagination-BQEm--kI.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-BWhFSr2d.js.map → StickyPagination-BQEm--kI.js.map} +1 -1
- package/dashboard/dist/assets/StreamMessageDetail-BTtw3GjX.js +2 -0
- package/dashboard/dist/assets/{StreamMessageDetail-BF0tM0cd.js.map → StreamMessageDetail-BTtw3GjX.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-Bv-KHY9s.js → SwimlaneTimeline-DdXxP4fO.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-Bv-KHY9s.js.map → SwimlaneTimeline-DdXxP4fO.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-B00uqhjX.js → TagInput-x9XTuqMb.js} +2 -2
- package/dashboard/dist/assets/{TagInput-B00uqhjX.js.map → TagInput-x9XTuqMb.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-Bzb_fuLy.js → TaskDetailPage-B8veYG4X.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-Bzb_fuLy.js.map → TaskDetailPage-B8veYG4X.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-CUsofm0X.js → TaskQueuePill-DSEQZ-HT.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-CUsofm0X.js.map → TaskQueuePill-DSEQZ-HT.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-CBezWaZL.js → TasksListPage-CsN1gZj5.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-CBezWaZL.js.map → TasksListPage-CsN1gZj5.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-CKHfTzat.js → TimeAgo-n182EcLx.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-CKHfTzat.js.map → TimeAgo-n182EcLx.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-Dsje8GH-.js → TimestampCell-2dlcQAfX.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-Dsje8GH-.js.map → TimestampCell-2dlcQAfX.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-DjvedZSn.js → ToolPill-B_e4eT77.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-DjvedZSn.js.map → ToolPill-B_e4eT77.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-3OcG18e5.js → ToolTestPanel-Bhnncc6M.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-3OcG18e5.js.map → ToolTestPanel-Bhnncc6M.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-DCtv91hH.js → TopicDetailPage-29lsNsqI.js} +3 -3
- package/dashboard/dist/assets/{TopicDetailPage-DCtv91hH.js.map → TopicDetailPage-29lsNsqI.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-DVGSNc_E.js → TopicsPage-KJ7_LAvo.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-DVGSNc_E.js.map → TopicsPage-KJ7_LAvo.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-xHAgkk8M.js → UserName-CMoFi9zb.js} +2 -2
- package/dashboard/dist/assets/{UserName-xHAgkk8M.js.map → UserName-CMoFi9zb.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-CWNxsS8a.js → WorkflowExecutionPage-Cymfx-Bp.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-CWNxsS8a.js.map → WorkflowExecutionPage-Cymfx-Bp.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-F1oKUzmc.js → WorkflowPill-B66_AnaY.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-F1oKUzmc.js.map → WorkflowPill-B66_AnaY.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowsDashboard-CqLN8spd.js +2 -0
- package/dashboard/dist/assets/WorkflowsDashboard-CqLN8spd.js.map +1 -0
- package/dashboard/dist/assets/{WorkflowsOverview-e7jWSj_n.js → WorkflowsOverview-0Rc2WT6q.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-e7jWSj_n.js.map → WorkflowsOverview-0Rc2WT6q.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CdAeam76.js → YamlWorkflowDetailPage-CARQ7_LN.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CdAeam76.js.map → YamlWorkflowDetailPage-CARQ7_LN.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-S_gKs2Di.js → YamlWorkflowsPage-B-7sz1nf.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-S_gKs2Di.js.map → YamlWorkflowsPage-B-7sz1nf.js.map} +1 -1
- package/dashboard/dist/assets/{agents-JE4aL07D.js → agents-zM43d5Yf.js} +2 -2
- package/dashboard/dist/assets/{agents-JE4aL07D.js.map → agents-zM43d5Yf.js.map} +1 -1
- package/dashboard/dist/assets/api-path-u2Jf9QXS.js +2 -0
- package/dashboard/dist/assets/api-path-u2Jf9QXS.js.map +1 -0
- package/dashboard/dist/assets/{bots-cAzKkDtQ.js → bots-D5BasOGz.js} +2 -2
- package/dashboard/dist/assets/{bots-cAzKkDtQ.js.map → bots-D5BasOGz.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-RBFXLAXF.js → capabilities-BT3PW9CZ.js} +2 -2
- package/dashboard/dist/assets/{capabilities-RBFXLAXF.js.map → capabilities-BT3PW9CZ.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-DGhv3rwI.js → controlplane-NpJr49rN.js} +2 -2
- package/dashboard/dist/assets/{controlplane-DGhv3rwI.js.map → controlplane-NpJr49rN.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-ne7dIaPa.js → escalation-DrzQolPG.js} +2 -2
- package/dashboard/dist/assets/{escalation-ne7dIaPa.js.map → escalation-DrzQolPG.js.map} +1 -1
- package/dashboard/dist/assets/escalation-columns-QzwmtD60.js +2 -0
- package/dashboard/dist/assets/escalation-columns-QzwmtD60.js.map +1 -0
- package/dashboard/dist/assets/index-B5w4Gjyk.js +6 -0
- package/dashboard/dist/assets/index-B5w4Gjyk.js.map +1 -0
- package/dashboard/dist/assets/{index-CByjpYlU.js → index-BCT4kqGR.js} +2 -2
- package/dashboard/dist/assets/{index-CByjpYlU.js.map → index-BCT4kqGR.js.map} +1 -1
- package/dashboard/dist/assets/{index-CgyucK0e.js → index-C69XvBfg.js} +2 -2
- package/dashboard/dist/assets/{index-CgyucK0e.js.map → index-C69XvBfg.js.map} +1 -1
- package/dashboard/dist/assets/index-CHw4Fl0t.css +1 -0
- package/dashboard/dist/assets/index-C_NwHTMh.js +2 -0
- package/dashboard/dist/assets/index-C_NwHTMh.js.map +1 -0
- package/dashboard/dist/assets/{index-DgzgRTNg.js → index-Cq0trGqf.js} +2 -2
- package/dashboard/dist/assets/{index-DgzgRTNg.js.map → index-Cq0trGqf.js.map} +1 -1
- package/dashboard/dist/assets/{index-DPJW96d2.js → index-DE0r9SEX.js} +26 -26
- package/dashboard/dist/assets/index-DE0r9SEX.js.map +1 -0
- package/dashboard/dist/assets/{index-BTqhAT6p.js → index-DH_CiD0W.js} +2 -2
- package/dashboard/dist/assets/{index-BTqhAT6p.js.map → index-DH_CiD0W.js.map} +1 -1
- package/dashboard/dist/assets/{index-C2l4GcZ7.js → index-K23FdS-T.js} +3 -3
- package/dashboard/dist/assets/{index-C2l4GcZ7.js.map → index-K23FdS-T.js.map} +1 -1
- package/dashboard/dist/assets/index-f6K1UNrn.js +2 -0
- package/dashboard/dist/assets/index-f6K1UNrn.js.map +1 -0
- package/dashboard/dist/assets/{index-BbJuC9kg.js → index-qr1fndqM.js} +2 -2
- package/dashboard/dist/assets/{index-BbJuC9kg.js.map → index-qr1fndqM.js.map} +1 -1
- package/dashboard/dist/assets/index-vKTvJ_li.js +2 -0
- package/dashboard/dist/assets/index-vKTvJ_li.js.map +1 -0
- package/dashboard/dist/assets/{index-CQDn-bLr.js → index-y-3ODtEE.js} +2 -2
- package/dashboard/dist/assets/{index-CQDn-bLr.js.map → index-y-3ODtEE.js.map} +1 -1
- package/dashboard/dist/assets/{index-QxAYCJ1S.js → index-y56Ds-LB.js} +2 -2
- package/dashboard/dist/assets/{index-QxAYCJ1S.js.map → index-y56Ds-LB.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-DzRpsm3D.js → knowledge-DSSATOTX.js} +2 -2
- package/dashboard/dist/assets/{knowledge-DzRpsm3D.js.map → knowledge-DSSATOTX.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-B1lc6nL4.js → mcp-CfJFVo5k.js} +2 -2
- package/dashboard/dist/assets/{mcp-B1lc6nL4.js.map → mcp-CfJFVo5k.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-CXuweaN3.js → mcp-query-DKVx2Q-X.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-CXuweaN3.js.map → mcp-query-DKVx2Q-X.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-D4VLWDvu.js → pipelines-BSWzE-6M.js} +2 -2
- package/dashboard/dist/assets/{pipelines-D4VLWDvu.js.map → pipelines-BSWzE-6M.js.map} +1 -1
- package/dashboard/dist/assets/{roles-CSpHRRu8.js → roles-t9HzhI5N.js} +2 -2
- package/dashboard/dist/assets/{roles-CSpHRRu8.js.map → roles-t9HzhI5N.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-CWUsKhM4.js → tasks-B7rUihoH.js} +2 -2
- package/dashboard/dist/assets/{tasks-CWUsKhM4.js.map → tasks-B7rUihoH.js.map} +1 -1
- package/dashboard/dist/assets/{topics-BXwstrzB.js → topics-PC2fEiyD.js} +2 -2
- package/dashboard/dist/assets/{topics-BXwstrzB.js.map → topics-PC2fEiyD.js.map} +1 -1
- package/dashboard/dist/assets/useDebouncedValue-BA5S7V54.js +2 -0
- package/dashboard/dist/assets/useDebouncedValue-BA5S7V54.js.map +1 -0
- package/dashboard/dist/assets/{useEventHooks-CjygrbYy.js → useEventHooks-DK9mw1cI.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-CjygrbYy.js.map → useEventHooks-DK9mw1cI.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-CsepDyR5.js → useNamespace-3IjtUtAw.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-CsepDyR5.js.map → useNamespace-3IjtUtAw.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-gWIG6akB.js → useYamlActivityEvents-uxukp3gO.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-gWIG6akB.js.map → useYamlActivityEvents-uxukp3gO.js.map} +1 -1
- package/dashboard/dist/assets/users-CC4B5Fm5.js +2 -0
- package/dashboard/dist/assets/users-CC4B5Fm5.js.map +1 -0
- package/dashboard/dist/assets/{vendor-icons-Dj2F0Jrb.js → vendor-icons-Dy5Jpknf.js} +114 -109
- package/dashboard/dist/assets/vendor-icons-Dy5Jpknf.js.map +1 -0
- package/dashboard/dist/assets/{workflows-C7Cam2Ok.js → workflows-S7MF1nNk.js} +2 -2
- package/dashboard/dist/assets/{workflows-C7Cam2Ok.js.map → workflows-S7MF1nNk.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-ChUOE22W.js → yaml-workflows-WfdaMHNn.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-ChUOE22W.js.map → yaml-workflows-WfdaMHNn.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/api/http/escalations.md +131 -10
- package/docs/api/http/roles.md +44 -9
- package/docs/api/http/users.md +15 -6
- package/docs/api/mcp/admin.md +164 -14
- package/docs/api/mcp/human-queue.md +34 -2
- package/docs/api/sdk/escalations.md +155 -2
- package/docs/api/sdk/roles.md +11 -0
- package/docs/api/sdk/users.md +26 -1
- package/docs/auth.md +1 -1
- package/docs/dashboard.md +5 -4
- package/docs/data.md +9 -2
- package/docs/faceted-routing.md +221 -0
- package/docs/hitl-guide.md +50 -0
- package/docs/iam.md +31 -0
- package/docs/mcp.md +8 -0
- package/package.json +2 -2
- package/dashboard/dist/assets/AdminDashboard-DZpduYdW.js +0 -2
- package/dashboard/dist/assets/AgentDetailPage-C-2iSaDs.js +0 -4
- package/dashboard/dist/assets/AgentDetailPage-C-2iSaDs.js.map +0 -1
- package/dashboard/dist/assets/AgentsPage-C3FztFd_.js +0 -2
- package/dashboard/dist/assets/AgentsPage-C3FztFd_.js.map +0 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-DIqdBCwe.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-DIqdBCwe.js.map +0 -1
- package/dashboard/dist/assets/CapabilitiesPage-DTfKCzBQ.js +0 -2
- package/dashboard/dist/assets/CopyableId-DaT0ZRHg.js +0 -2
- package/dashboard/dist/assets/CopyableId-DaT0ZRHg.js.map +0 -1
- package/dashboard/dist/assets/McpQueryPage-Db1LUKVs.js +0 -2
- package/dashboard/dist/assets/McpQueryPage-Db1LUKVs.js.map +0 -1
- package/dashboard/dist/assets/McpRunsPage--tgT5uo7.js +0 -2
- package/dashboard/dist/assets/McpRunsPage--tgT5uo7.js.map +0 -1
- package/dashboard/dist/assets/OperatorDashboard-BWVUbJkZ.js +0 -2
- package/dashboard/dist/assets/OperatorDashboard-BWVUbJkZ.js.map +0 -1
- package/dashboard/dist/assets/PageHeader-Bnt2iQQa.js +0 -2
- package/dashboard/dist/assets/PageHeader-Bnt2iQQa.js.map +0 -1
- package/dashboard/dist/assets/PriorityBadge-DfQY9St9.js +0 -2
- package/dashboard/dist/assets/PriorityBadge-DfQY9St9.js.map +0 -1
- package/dashboard/dist/assets/ProcessesListPage-CWiRM_h3.js +0 -2
- package/dashboard/dist/assets/ProcessesListPage-CWiRM_h3.js.map +0 -1
- package/dashboard/dist/assets/RolePill-DQTT1s9v.js +0 -2
- package/dashboard/dist/assets/RolePill-DQTT1s9v.js.map +0 -1
- package/dashboard/dist/assets/RowActions-Dg-Fsm5O.js +0 -2
- package/dashboard/dist/assets/RowActions-Dg-Fsm5O.js.map +0 -1
- package/dashboard/dist/assets/StreamMessageDetail-BF0tM0cd.js +0 -2
- package/dashboard/dist/assets/WorkflowsDashboard-M13lIaw7.js +0 -2
- package/dashboard/dist/assets/WorkflowsDashboard-M13lIaw7.js.map +0 -1
- package/dashboard/dist/assets/escalation-columns-DqTkKbCv.js +0 -2
- package/dashboard/dist/assets/escalation-columns-DqTkKbCv.js.map +0 -1
- package/dashboard/dist/assets/index-CEpw_Fh8.js +0 -2
- package/dashboard/dist/assets/index-CEpw_Fh8.js.map +0 -1
- package/dashboard/dist/assets/index-ClvYSNZd.css +0 -1
- package/dashboard/dist/assets/index-CucXk58o.js +0 -6
- package/dashboard/dist/assets/index-CucXk58o.js.map +0 -1
- package/dashboard/dist/assets/index-DPJW96d2.js.map +0 -1
- package/dashboard/dist/assets/index-DeZhNCf5.js +0 -2
- package/dashboard/dist/assets/index-DeZhNCf5.js.map +0 -1
- package/dashboard/dist/assets/index-Do8Xp3pa.js +0 -2
- package/dashboard/dist/assets/index-Do8Xp3pa.js.map +0 -1
- package/dashboard/dist/assets/users-DvhHbR0R.js +0 -2
- package/dashboard/dist/assets/users-DvhHbR0R.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-Dj2F0Jrb.js.map +0 -1
package/docs/data.md
CHANGED
|
@@ -74,6 +74,11 @@ backward-compatible **view** over it — `SELECT *` plus a computed `available`
|
|
|
74
74
|
column — so existing read queries and the public API are unchanged. Indexes are
|
|
75
75
|
managed by the SDK on `hmsh_escalations` (see below).
|
|
76
76
|
|
|
77
|
+
Role read/write scope does **not** add columns here. An escalation carries a `role`
|
|
78
|
+
and an optional `assigned_to`; work-surface scope lives on the membership table
|
|
79
|
+
(`lt_user_roles`) and is applied at read time. `condition()` / `conditionLT()` and
|
|
80
|
+
the escalation engine are unaffected.
|
|
81
|
+
|
|
77
82
|
The columns below are the `hmsh_escalations` table. The public API record
|
|
78
83
|
(`LTEscalationRecord`) is mapped from these: the JSONB `envelope` /
|
|
79
84
|
`escalation_payload` / `resolver_payload` are serialized to JSON **strings**, and
|
|
@@ -179,12 +184,14 @@ Maps users to roles. Each user can hold multiple roles with different permission
|
|
|
179
184
|
|--------|------|---------|-------------|
|
|
180
185
|
| `user_id` | `UUID NOT NULL` | — | FK to `lt_users(id)`, CASCADE on delete |
|
|
181
186
|
| `role` | `TEXT NOT NULL` | — | Role name (e.g., `reviewer`, `senior-reviewer`) |
|
|
182
|
-
| `type` | `TEXT NOT NULL` | `'member'` | `superadmin`, `admin`, or `member` |
|
|
187
|
+
| `type` | `TEXT NOT NULL` | `'member'` | `superadmin`, `admin`, or `member` — the management tier |
|
|
188
|
+
| `read_scope` | `TEXT NOT NULL` | `'all'` | `self` or `all` — search breadth for a `member`: which escalations in the role queue the member sees. `self` = items where `assigned_to = user`; `all` = the whole queue. Ignored for `admin`/`superadmin`, which always see the whole queue. |
|
|
189
|
+
| `write_scope` | `TEXT NOT NULL` | `'all'` | `none`, `self`, or `all` — claim/ack/delete breadth for a `member`. `none` = read-only; `self` = items assigned to the member; `all` = the whole queue. Ignored for `admin`/`superadmin`. |
|
|
183
190
|
| `created_at` | `TIMESTAMPTZ NOT NULL` | `NOW()` | When the role was assigned |
|
|
184
191
|
|
|
185
192
|
Primary key: `(user_id, role)` — a user can hold each role at most once.
|
|
186
193
|
|
|
187
|
-
Type is enforced by a CHECK constraint: `type IN ('superadmin', 'admin', 'member')`.
|
|
194
|
+
Type is enforced by a CHECK constraint: `type IN ('superadmin', 'admin', 'member')`. Scope is enforced by CHECK constraints: `read_scope IN ('self', 'all')`, `write_scope IN ('none', 'self', 'all')`, and **write ⊆ read** — `write_scope = 'all'` requires `read_scope = 'all'` (a member cannot act on what it cannot see). Both scopes default to `all`, the full-queue worker.
|
|
188
195
|
|
|
189
196
|
### lt_bot_api_keys
|
|
190
197
|
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# Faceted Routing
|
|
2
|
+
|
|
3
|
+
The escalation queue is more than a HITL inbox — it is a durable, queryable pool of work
|
|
4
|
+
that any number of consumers can search and atomically claim by its **facets**. Faceted
|
|
5
|
+
routing is the platform surface for that: a composable query language over the queue and a
|
|
6
|
+
set of atomic claim primitives. The platform supplies the surface; the *policy* — what a
|
|
7
|
+
facet means, how capability and priority map onto it, the matching loop — is the consuming
|
|
8
|
+
app's. The [print-routing example](../examples/workflows/print-routing/README.md) is a full
|
|
9
|
+
worked policy built entirely on these primitives.
|
|
10
|
+
|
|
11
|
+
## Contents
|
|
12
|
+
|
|
13
|
+
- [The model](#the-model)
|
|
14
|
+
- [The query — `FacetQuery`](#the-query--facetquery)
|
|
15
|
+
- [Reads](#reads)
|
|
16
|
+
- [Atomic claims](#atomic-claims)
|
|
17
|
+
- [The dispatcher pattern](#the-dispatcher-pattern)
|
|
18
|
+
- [Recording the outcome on resolve](#recording-the-outcome-on-resolve)
|
|
19
|
+
- [Safety](#safety)
|
|
20
|
+
|
|
21
|
+
## The model
|
|
22
|
+
|
|
23
|
+
Every escalation row carries a `role` (the hard isolation boundary) and a `metadata` JSONB
|
|
24
|
+
object (the soft facets a late-binding consumer queries, sorts, and claims by). Routing
|
|
25
|
+
work is a funnel over those columns:
|
|
26
|
+
|
|
27
|
+
- **Capability** — the hard wall — is the `role`. A consumer bound to one role can never
|
|
28
|
+
see another role's work. Soft capability is `metadata @>` containment.
|
|
29
|
+
- **Preference / priority** — ordering — is `orderBy` over top-level columns and facets.
|
|
30
|
+
- **Capacity** — how much to take — is the page `limit` of a claim.
|
|
31
|
+
|
|
32
|
+
An **order** (or any multi-unit job) is a set of rows sharing an `origin_id`; its unit
|
|
33
|
+
count lives in a metadata facet so a group can be claimed all-or-nothing only when complete.
|
|
34
|
+
|
|
35
|
+
## The query — `FacetQuery`
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
interface FacetQuery {
|
|
39
|
+
role?: string; // hard isolation (exact)
|
|
40
|
+
roles?: string[]; // role = ANY(...)
|
|
41
|
+
facets?: Record<string, any>; // metadata @> facets — required (AND), GIN-served
|
|
42
|
+
block?: Record<string, any>[]; // NOT (metadata @> ANY(block)) — exclusion list
|
|
43
|
+
range?: { facet: string; op: '<' | '<=' | '>' | '>=' | '='; value: number }[];
|
|
44
|
+
exists?: string[]; // metadata ? key — facet must be present
|
|
45
|
+
status?: string; // e.g. 'pending'
|
|
46
|
+
available?: boolean; // true = unclaimed/expired only; false = held now
|
|
47
|
+
orderBy?: { field: string; direction?: 'asc' | 'desc'; numeric?: boolean }[];
|
|
48
|
+
limit?: number;
|
|
49
|
+
offset?: number;
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`orderBy.field` is either a whitelisted top-level column (`priority`, `created_at`,
|
|
54
|
+
`updated_at`, `status`, `role`) or a metadata path written as `metadata.<key>` (extracted as
|
|
55
|
+
text, or numeric when `numeric` is set). Every value is parameterized; only validated column
|
|
56
|
+
names / metadata keys and a fixed operator set are ever interpolated.
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
// Pending, available diabetic-certified work needing PLA, soonest-deadline first.
|
|
60
|
+
const query: FacetQuery = {
|
|
61
|
+
role: 'print-farm-diabetic',
|
|
62
|
+
status: 'pending',
|
|
63
|
+
available: true,
|
|
64
|
+
facets: { filament: 'pla' },
|
|
65
|
+
orderBy: [{ field: 'metadata.mustCompleteBy', numeric: true, direction: 'asc' }],
|
|
66
|
+
};
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Reads
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { searchByFacets, searchGroups, countByFacets } from '@hotmeshio/long-tail';
|
|
73
|
+
|
|
74
|
+
// Item-level: filter/sort over columns and metadata facets.
|
|
75
|
+
const { escalations, total } = await searchByFacets(query);
|
|
76
|
+
|
|
77
|
+
// Order-level: each row is an origin group with its unit count, availability and
|
|
78
|
+
// completeness — what a batched dispatcher reads to page by capacity.
|
|
79
|
+
const groups = await searchGroups(query, { sizeFacet: 'orderSize', limit: 10 });
|
|
80
|
+
|
|
81
|
+
// Aggregate: capacity / in-flight soft-limit checks.
|
|
82
|
+
const inFlight = await countByFacets({ role: 'print-farm-diabetic', available: false });
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Atomic claims
|
|
86
|
+
|
|
87
|
+
Two claim primitives, both `FOR UPDATE SKIP LOCKED` so many consumers run without
|
|
88
|
+
contention. Each takes the `FacetQuery`, a `consumer` id, and options.
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { claimGroups, claimByFacets } from '@hotmeshio/long-tail';
|
|
92
|
+
|
|
93
|
+
// Claim whole orders (origin groups), all-or-nothing, in rank order. The page `limit`
|
|
94
|
+
// is how many consumers/printers are free, so a dependent grabs exactly what it can
|
|
95
|
+
// distribute. A group is only eligible when complete (member count = declared size).
|
|
96
|
+
const orders = await claimGroups(query, 'broker-1', { limit: 4, sizeFacet: 'orderSize' });
|
|
97
|
+
|
|
98
|
+
// Claim individual rows by facet — the single-row sibling. Locks up to `limit` available
|
|
99
|
+
// rows in rank order. With { allOrNone: true } the claim commits only when the full limit
|
|
100
|
+
// is acquired, otherwise it rolls back and returns [] — the all-or-none lock a dispatcher
|
|
101
|
+
// wants over a counted set it anticipated.
|
|
102
|
+
const printers = await claimByFacets(
|
|
103
|
+
{ role: 'printer-pool-diabetic', facets: { state: 'ready' } },
|
|
104
|
+
'broker-1',
|
|
105
|
+
{ limit: 4 },
|
|
106
|
+
);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
A claim sets `assigned_to` + `assigned_until` (default 30 minutes). Availability is a
|
|
110
|
+
query, not a flag: a row is held iff `assigned_to` is set and `assigned_until > NOW()`.
|
|
111
|
+
Resolve, release, or let the claim expire to return it to the pool.
|
|
112
|
+
|
|
113
|
+
## The dispatcher pattern
|
|
114
|
+
|
|
115
|
+
The primitives compose into a market: pull a *page* of complete orders sized to how many
|
|
116
|
+
consumers are free, then distribute one per consumer. Reads go through the
|
|
117
|
+
`public.lt_escalations` view (it adds the computed `available` flag); atomic claims run on
|
|
118
|
+
the shared `public.hmsh_escalations` table — the same raw-SQL-on-the-shared-table pattern as
|
|
119
|
+
the rest of the escalation service. Metadata facets use the GIN index (`@>`).
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// 1. Anticipate supply.
|
|
123
|
+
const free = await searchByFacets({ role: 'printer-pool', available: true, facets: { state: 'ready' } });
|
|
124
|
+
// 2. Claim that much demand by priority.
|
|
125
|
+
const orders = await claimGroups(demandQuery, consumer, { limit: free.escalations.length });
|
|
126
|
+
// 3. Lock the printers for the claimed orders, all-or-none.
|
|
127
|
+
const printers = await claimByFacets(supplyQuery, consumer, { limit: orders.length, allOrNone: true });
|
|
128
|
+
// 4. Pair, do the work, resolve both.
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
See the [print-routing example](../examples/workflows/print-routing/README.md) for the full
|
|
132
|
+
two-sided market, carry-forward under contention, and the inspection/convergence loop.
|
|
133
|
+
|
|
134
|
+
## Recording the outcome on resolve
|
|
135
|
+
|
|
136
|
+
A row is created carrying **intent** — the facets that route and claim it. Resolving it can
|
|
137
|
+
record the **outcome** onto the same row: pass a `metadata` patch and it is merged (not
|
|
138
|
+
replaced) into the GIN-indexed metadata in the same atomic UPDATE, on the winning resolve
|
|
139
|
+
only. "What actually happened" becomes `@>`-queryable next to "what was asked".
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
import { resolveEscalation } from '@hotmeshio/long-tail';
|
|
143
|
+
|
|
144
|
+
// The work is done; resolve the row AND stamp the outcome onto it — one atomic call.
|
|
145
|
+
await resolveEscalation(rowId, { result: 'success' }, {
|
|
146
|
+
outcome: 'success',
|
|
147
|
+
unitsPrinted: 6,
|
|
148
|
+
});
|
|
149
|
+
// Duration needs no facet: the row's own created_at → resolved_at is the elapsed time.
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The third argument is distinct from the second: `resolverPayload` (arg 2) is delivered to a
|
|
153
|
+
waiting workflow as `condition()`'s return value and is **not** indexed; the `metadata` patch
|
|
154
|
+
(arg 3) is the durable, queryable record on the row. With both, the row alone answers what was
|
|
155
|
+
asked, what happened, and how long it took:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
searchByFacets({ role: 'printer-pool-diabetic', facets: { state: 'printing', outcome: 'success' } });
|
|
159
|
+
// → every completed job: which consumer, which origin, how long — no side table to reconcile
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
The print farm leans on this: a printer resolves its in-flight `printing` row with the run's
|
|
163
|
+
result and units in one atomic call, so the supply pond is also the production log — and the
|
|
164
|
+
row's `created_at` → `resolved_at` is the print duration, no stored field required.
|
|
165
|
+
|
|
166
|
+
## The human / operations query
|
|
167
|
+
|
|
168
|
+
The same query language is also the operations team's read surface. Where the dispatcher
|
|
169
|
+
sections above target a **single pond** for a workflow consumer, a **person** — a superadmin, or
|
|
170
|
+
a member of several roles — queries "what work needs doing / was done" across **their** roles by
|
|
171
|
+
the same facets, through the scoped list API.
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { createClient } from '@hotmeshio/long-tail/sdk';
|
|
175
|
+
const lt = createClient({ auth }); // auth carries the caller's userId
|
|
176
|
+
|
|
177
|
+
// Faceted, role-scoped, paginated — the filter AND the count run in SQL.
|
|
178
|
+
const res = await lt.escalations.list({
|
|
179
|
+
status: 'pending',
|
|
180
|
+
facets: { flags: 'too_short' }, // metadata @> (GIN-served)
|
|
181
|
+
range: [{ facet: 'confidence', op: '<=', value: 0.7 }],
|
|
182
|
+
exists: ['needsReview'],
|
|
183
|
+
block: [{ outcome: 'success' }], // exclude completed
|
|
184
|
+
orderBy: [{ field: 'metadata.confidence', numeric: true, direction: 'asc' }],
|
|
185
|
+
limit: 50, offset: 0,
|
|
186
|
+
});
|
|
187
|
+
// res.data → { escalations, total }
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`list` and `listAvailable` accept the FacetQuery elements (`facets`, `block`, `range`, `exists`,
|
|
191
|
+
`roles`, `available`, `orderBy`) on top of the plain filters. When any are present the request
|
|
192
|
+
runs through the scoped faceted query; otherwise the simple list path is used.
|
|
193
|
+
|
|
194
|
+
**Role scope is enforced in SQL, not in the controller.** The result is the read-scope predicate
|
|
195
|
+
ANDed with the facets:
|
|
196
|
+
|
|
197
|
+
- **superadmin / admin-of-admin** (global) — every role's queue, no role filter.
|
|
198
|
+
- **`read_all` on a role** — the whole pond for that role.
|
|
199
|
+
- **`read_self` on a role** — only items assigned to the caller (`assigned_to = me`).
|
|
200
|
+
|
|
201
|
+
A caller may **narrow** within their scope (pass `role`/`roles`) but can never **widen** past it —
|
|
202
|
+
a `role` they don't hold simply matches nothing. The page total is computed by the same WHERE, so
|
|
203
|
+
pagination stays correct; the controller never filters a fetched page client-side.
|
|
204
|
+
|
|
205
|
+
Over HTTP the faceted elements are JSON-encoded query params, so the whole query rides on a GET
|
|
206
|
+
URL and the dashboard's copy-URL / copy-curl reproduces the exact request:
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
GET /api/escalations?status=pending&facets=%7B%22flags%22%3A%22too_short%22%7D&range=%5B%7B%22facet%22%3A%22confidence%22%2C%22op%22%3A%22%3C%3D%22%2C%22value%22%3A0.7%7D%5D
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Safety
|
|
213
|
+
|
|
214
|
+
- **Parameterized** — every value is a bound parameter; only audited column names, metadata
|
|
215
|
+
keys (strict `^[a-zA-Z0-9_]+$`), and a fixed operator set are interpolated.
|
|
216
|
+
- **Atomic** — claims are single transactions with `FOR UPDATE SKIP LOCKED`; group claims
|
|
217
|
+
re-check completeness *inside* the lock, so concurrent dispatchers never split a group or
|
|
218
|
+
double-claim a row.
|
|
219
|
+
- **Durable consumers** — because the surface is a query, a consumer that holds a claim it
|
|
220
|
+
cannot yet place can carry it across `continueAsNew` and converge later rather than
|
|
221
|
+
releasing — the durable workflow is the coordinator, not a distributed transaction.
|
package/docs/hitl-guide.md
CHANGED
|
@@ -158,6 +158,29 @@ export async function reviewWorkflow(envelope: LTEnvelope) {
|
|
|
158
158
|
|
|
159
159
|
---
|
|
160
160
|
|
|
161
|
+
## Recording the Outcome on Resolution
|
|
162
|
+
|
|
163
|
+
An escalation row is created carrying **intent** — what was asked, who it routed to. Resolving it can stamp the **outcome** onto the same row: every resolve surface takes an optional `metadata` patch, merged into the row's GIN-indexed metadata.
|
|
164
|
+
|
|
165
|
+
| Surface | How to pass it |
|
|
166
|
+
|---------|----------------|
|
|
167
|
+
| HTTP | `metadata` in the resolve body (`POST /api/escalations/:id/resolve`, `/resolve-by-signal-key`) |
|
|
168
|
+
| SDK facade | `lt.escalations.resolve({ id, resolverPayload, metadata })` |
|
|
169
|
+
| MCP | `metadata` arg on `claim_and_resolve` / `resolve_escalation` |
|
|
170
|
+
| In-process library | `resolveEscalation(id, payload, metadata)` / `resolveEscalationBySignalKey(signalKey, payload, metadata)` |
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
await lt.escalations.resolve({
|
|
174
|
+
id,
|
|
175
|
+
resolverPayload: { approved: true }, // resumes the workflow; not indexed
|
|
176
|
+
metadata: { outcome: 'approved', reviewedBy: 'alice', durationMs: elapsed },
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The patch is distinct from the resolver payload: the payload resumes the paused workflow and is not indexed; the metadata patch is the durable, queryable record on the row. Use it for the audit trail and analytics — disposition, reviewer, time-to-resolve — so the escalation table answers *what was asked, what was decided, and how long it took* without a parallel log.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
161
184
|
## JSON Schema Form Authoring
|
|
162
185
|
|
|
163
186
|
The dashboard renders forms automatically from JSON Schema. No frontend code needed.
|
|
@@ -456,6 +479,33 @@ await ltCreateEscalation({
|
|
|
456
479
|
});
|
|
457
480
|
```
|
|
458
481
|
|
|
482
|
+
### Work-Surface Scope
|
|
483
|
+
|
|
484
|
+
A `member` of a role carries a work-surface scope that narrows what they see and act on within that queue: `read_scope` (`self` | `all`) governs which escalations they see, and `write_scope` (`none` | `self` | `all`) governs which they can claim, resolve, or cancel. `self` means escalations assigned to that member (`assigned_to = user`); `all` means the whole role queue. `admin` and `superadmin` always work the whole queue. See the [Roles API](api/http/roles.md#work-surface-scope) for the five member profiles and the assignment contract.
|
|
485
|
+
|
|
486
|
+
Scope is a property of the **membership** (`lt_user_roles`), not of the escalation. The escalation engine is unchanged: `condition()` / `conditionLT()`, `ltCreateEscalation`, and the interceptor write escalation rows (`hmsh_escalations`) exactly as before — an escalation carries a `role` and an optional `assigned_to`, with no scope column. Scope is resolved at read time, when a *user* lists or acts on the queue. Escalating to a role that does not exist yet still registers the role name only — roles are typeless; `type` and scope are set per user when the role is granted. The one place scope affects creation is the standalone `POST /api/escalations` HTTP endpoint, which requires `write_scope=all`; workflow-emitted escalations (`conditionLT`, interceptor returns, `ltCreateEscalation`) do not pass through that check.
|
|
487
|
+
|
|
488
|
+
### One-Time and Pre-Assigned Users
|
|
489
|
+
|
|
490
|
+
To route a single item to a named person, assign the escalation to them and provision them with `read_scope=self` + `write_scope=self`. The workflow sets `assigned_to` to the person's user ID (a pre-claim) when it creates the escalation, then provisions or updates that user as a `member` with self/self scope on the target role. They land directly on that one item — a just-in-time form scoped by RBAC, with no access to the rest of the queue and no direct table access. An update or follow-up is simply another workflow firing another escalation to that same person.
|
|
491
|
+
|
|
492
|
+
```typescript
|
|
493
|
+
// Pre-assign the escalation to a specific person and route a one-time form to them
|
|
494
|
+
await ltCreateEscalation({
|
|
495
|
+
role: 'customer-triage',
|
|
496
|
+
assigned_to: userId, // pre-claim — durable, keyed off the user, not the soft-lock TTL
|
|
497
|
+
description: 'Confirm your shipping address',
|
|
498
|
+
metadata: {
|
|
499
|
+
form_schema: {
|
|
500
|
+
title: 'Confirm Address',
|
|
501
|
+
properties: { address: { type: 'string' }, confirmed: { type: 'boolean' } },
|
|
502
|
+
required: ['confirmed'],
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
});
|
|
506
|
+
// The person is provisioned as a member of `customer-triage` with read_scope=self, write_scope=self.
|
|
507
|
+
```
|
|
508
|
+
|
|
459
509
|
### Escalation Chains
|
|
460
510
|
|
|
461
511
|
Users can escalate to other roles via the "Escalate" tab:
|
package/docs/iam.md
CHANGED
|
@@ -14,6 +14,37 @@ Each workflow execution carries three pieces of identity:
|
|
|
14
14
|
|
|
15
15
|
**Credentials** — OAuth tokens and API keys available to the principal. Resolved at runtime through a cascade: principal's stored credentials, then the initiating user's credentials, then system environment variables.
|
|
16
16
|
|
|
17
|
+
## Work-Surface Scope
|
|
18
|
+
|
|
19
|
+
Identity says *who* a principal is. Work-surface scope says *what* that principal sees and does within a role's queue. It is the fourth axis, orthogonal to initiator, principal, and credentials.
|
|
20
|
+
|
|
21
|
+
A role is a task queue with four verbs — **search**, **claim**, **ack** (resolve), **delete** (cancel). A `member` grant carries two scope axes stored on `lt_user_roles` that set the breadth of those verbs:
|
|
22
|
+
|
|
23
|
+
- `read_scope` (`self` | `all`, default `all`) — governs **search**: which escalations the member sees. `self` = items assigned to the member (`assigned_to = user`); `all` = the whole role queue.
|
|
24
|
+
- `write_scope` (`none` | `self` | `all`, default `all`) — governs **claim / ack / delete**: which escalations the member may act on. `none` = read-only.
|
|
25
|
+
|
|
26
|
+
The constraint is **write ⊆ read** — you cannot act on what you cannot see — so `write_scope=all` requires `read_scope=all`. `admin` and `superadmin` ignore scope and always act on the whole queue. The default `all`/`all` is the full-queue worker.
|
|
27
|
+
|
|
28
|
+
The five member profiles:
|
|
29
|
+
|
|
30
|
+
| read_scope | write_scope | Profile |
|
|
31
|
+
|-----------|------------|---------|
|
|
32
|
+
| `all` | `all` | Full worker — search and act on the whole queue (default) |
|
|
33
|
+
| `all` | `self` | See the whole queue, act only on own items (e.g. a chat-style room) |
|
|
34
|
+
| `self` | `self` | Own items only — a one-time user filling in their pre-assigned form |
|
|
35
|
+
| `all` | `none` | Read-only observer / auditor of the queue |
|
|
36
|
+
| `self` | `none` | Read-only view of one's own items |
|
|
37
|
+
|
|
38
|
+
### One-Time Users
|
|
39
|
+
|
|
40
|
+
Scope makes limited-surface users first-class. A workflow assigns an escalation to a named person — a pre-claim, setting `assigned_to` to that user — and provisions them as a `member` with `read_scope=self` and `write_scope=self`. They see and act on exactly that one item: a just-in-time form surface scoped by RBAC, with no access to the rest of the queue and no direct table access. A follow-up or update is simply another workflow firing another escalation to that same person. Because `self` scope keys off durable `assigned_to` (independent of the soft-lock claim TTL), the assignment persists until the workflow resolves it.
|
|
41
|
+
|
|
42
|
+
See the [Roles API](api/http/roles.md#work-surface-scope) for the assignment contract and the [HITL Guide](hitl-guide.md#role-based-routing) for the workflow-side flow.
|
|
43
|
+
|
|
44
|
+
### Enforcement
|
|
45
|
+
|
|
46
|
+
Scope folds into the SQL, so it is atomic with no TOCTOU window. Read scope becomes part of the escalation search query — a member sees a row when `role ∈ allRoles OR (role ∈ selfRoles AND assigned_to = me)`. Write scope folds into the atomic resolve-by-metadata query and gates the by-id claim/resolve/cancel paths. `assigned_to` is indexed, so `self` scope scales to large queues.
|
|
47
|
+
|
|
17
48
|
## Workflow Types and IAM
|
|
18
49
|
|
|
19
50
|
Long Tail has three workflow types (see the [Workflows Guide](workflows.md#three-workflow-types) for full details). IAM applies to all three:
|
package/docs/mcp.md
CHANGED
|
@@ -354,6 +354,14 @@ Returns:
|
|
|
354
354
|
|
|
355
355
|
Returns `isError: true` if the escalation isn't available (already claimed, already resolved, or doesn't exist).
|
|
356
356
|
|
|
357
|
+
### Scope and one-time users
|
|
358
|
+
|
|
359
|
+
An escalation created here lands in the target role's queue, where each member sees and acts on it according to their work-surface scope. A role membership carries a `type` (`member`, `admin`, or `superadmin`) plus two scope axes: `read_scope` (`self` | `all`) sets which escalations a member sees, and `write_scope` (`none` | `self` | `all`) sets which they may claim and resolve, with write ⊆ read. A `read_all` member sees the whole queue; a `read_self` member sees only items assigned to them. An `admin` or `superadmin` always acts on the whole queue. The defaults, `all`/`all`, are the full-queue worker.
|
|
360
|
+
|
|
361
|
+
`get_available_work` returns the pending, unassigned items for a role — the shared pool that whole-queue (`write_all`) workers draw from. A `write_self` member does not pull from the pool; their item is pre-assigned to them.
|
|
362
|
+
|
|
363
|
+
The one-time-user pattern builds on this. A workflow routes a single escalation to a named person by setting `assigned_to` when it creates the escalation — the `assigned_to` field on `escalate_and_wait` pre-claims the item — and that person is provisioned as a `member` of the role with `read_self` + `write_self`. They then see and act on exactly that one item: a scoped, single-item surface with no access to the rest of the queue. The scoped membership is provisioned through the platform's user and escalation APIs (see the [Roles API](api/http/roles.md)); the escalate tools supply the `assigned_to` pre-claim.
|
|
364
|
+
|
|
357
365
|
### Connecting
|
|
358
366
|
|
|
359
367
|
**In-process (testing or co-located agents):**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hotmeshio/long-tail",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Long Tail Workflows — Durable AI workflows with human-in-the-loop escalation. Powered by PostgreSQL.",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"@anthropic-ai/sdk": "^0.92.0",
|
|
71
71
|
"@aws-sdk/client-s3": "^3.1017.0",
|
|
72
72
|
"@aws-sdk/s3-request-presigner": "^3.1045.0",
|
|
73
|
-
"@hotmeshio/hotmesh": "^0.
|
|
73
|
+
"@hotmeshio/hotmesh": "^0.24.1",
|
|
74
74
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
75
75
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.215.0",
|
|
76
76
|
"@opentelemetry/resources": "^2.5.1",
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{j as o}from"./vendor-query-B2UbickB.js";import{c as n}from"./tasks-CWUsKhM4.js";import{s as m}from"./index-DPJW96d2.js";import{f as c}from"./useEventHooks-CjygrbYy.js";import{u}from"./mcp-B1lc6nL4.js";import{P as d}from"./PageHeaderWithStats-BuKc9MKt.js";import"./vendor-react-CXumBFUA.js";import"./vendor-icons-Dj2F0Jrb.js";function j(){var a;c();const{data:t}=n({limit:1}),{data:e}=m({status:"pending",limit:1}),{data:s}=u(),r=((a=s==null?void 0:s.servers)==null?void 0:a.filter(i=>i.status==="connected").length)??0,l=s?`${r}/${s.total}`:"—";return o.jsx("div",{children:o.jsx(d,{title:"Admin",stats:[{label:"Tasks",value:(t==null?void 0:t.total)??"—"},{label:"Pending Escalations",value:(e==null?void 0:e.total)??"—",dotClass:"bg-status-pending"},{label:"MCP Servers",value:l},{label:"System",value:"Healthy",dotClass:"bg-status-success"}]})})}export{j as AdminDashboard};
|
|
2
|
-
//# sourceMappingURL=AdminDashboard-DZpduYdW.js.map
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import{j as e,a as y}from"./vendor-query-B2UbickB.js";import{a as D,b as L,c as R}from"./agents-JE4aL07D.js";import{u as W,b as K,N as M}from"./index-DPJW96d2.js";import{u as z,E,C as S}from"./CronLabel-DrGWtaSY.js";import{i as I}from"./useEventHooks-CjygrbYy.js";import{W as N}from"./WorkflowPill-F1oKUzmc.js";import{a as U,B as F,Q as H,P as G,aK as J,q as O,aL as Q,R as _,a7 as X,d as Y,aM as V}from"./vendor-icons-Dj2F0Jrb.js";import{e as Z,c as ee}from"./vendor-react-CXumBFUA.js";function te(a){return new Date(a).toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit",second:"2-digit"})}function u({icon:a,color:i,children:c,actions:h}){return e.jsxs("div",{className:"flex items-center justify-between mb-3 pb-2 border-b border-surface-border",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(a,{className:`w-4 h-4 ${i}`,strokeWidth:1.5}),e.jsx("h2",{className:"text-xs font-semibold uppercase tracking-widest text-accent/80",children:c})]}),h]})}function j({text:a}){return e.jsx("p",{className:"text-[11px] text-text-quaternary py-2",children:a})}let se=0;function ae(a){const[i,c]=y.useState([]),[h,d]=y.useState(!1),t=y.useCallback(r=>{var m,g,p;if((m=r.type)!=null&&m.startsWith("mesh."))return;const x=r.activityName||((g=r.data)==null?void 0:g.domain)||((p=r.workflowId)==null?void 0:p.slice(0,16))||"";c(f=>[{id:++se,type:r.type,timestamp:r.timestamp,label:x},...f].slice(0,10)),d(!0),setTimeout(()=>d(!1),2e3)},[]);return K(a?`${M}.system.agent.${a}.>`:"",t),{events:i,pulse:h}}function me(){var b,w,k,C,$;const{id:a}=Z(),i=ee(),{data:c}=W(),d=!!((b=c==null?void 0:c.ai)!=null&&b.enabled)?"Agent":"Automation",{data:t,isLoading:r}=D(a??null),{data:x}=z(a??null),m=L(),g=R(),{events:p,pulse:f}=ae(a);if(I(),r)return e.jsxs("div",{className:"animate-pulse space-y-4",children:[e.jsx("div",{className:"h-8 bg-surface-sunken rounded w-48"}),e.jsx("div",{className:"h-40 bg-surface-sunken rounded"})]});if(!t)return e.jsxs("div",{className:"flex flex-col items-center justify-center py-20 text-center",children:[e.jsx(U,{className:"w-12 h-12 text-text-quaternary mb-4",strokeWidth:1}),e.jsxs("h2",{className:"text-lg font-medium text-text-primary mb-2",children:[d," not found"]}),e.jsxs("button",{onClick:()=>i("/agents"),className:"text-sm text-accent hover:text-accent-hover transition-colors",children:["Back to ",d.toLowerCase(),"s"]})]});const A=t.status==="active"?"bg-emerald-400":t.status==="paused"?"bg-amber-400":t.status==="error"?"bg-red-400":"bg-zinc-500",n=(x==null?void 0:x.subscriptions)??[],P=t.status==="active"?"Active":t.status==="paused"?"Paused":t.status==="error"?"Error":"Inactive",l=(w=t.behaviors)==null?void 0:w.schedules,v=(k=t.behaviors)==null?void 0:k.cron,o=(l==null?void 0:l.length)||(v?1:0),q=()=>{const s=[`Pause "${t.id}"?`,"","This will:",n.length>0?`• Stop ${n.length} event subscription${n.length!==1?"s":""}`:null,o>0?`• Stop ${o} schedule${o!==1?"s":""}`:null,"","Knowledge and workflow history are preserved. You can reactivate anytime."].filter(Boolean).join(`
|
|
2
|
-
`);confirm(s)&&m.mutate({id:t.id,status:"paused"})},T=()=>{const s=[`Delete "${t.id}"?`,"","This permanently removes:","• The agent configuration",n.length>0?`• ${n.length} event subscription${n.length!==1?"s":""}`:null,o>0?`• ${o} schedule${o!==1?"s":""}`:null,"","Knowledge entries and workflow history are preserved."].filter(Boolean).join(`
|
|
3
|
-
`);confirm(s)&&g.mutate(t.id,{onSuccess:()=>i("/agents")})};return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-start justify-between mb-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("h1",{className:"text-3xl font-light text-text-primary",children:[d,": ",t.id]}),e.jsx("button",{onClick:()=>{window.location.hash="#docs:agents.md"},className:"text-text-quaternary hover:text-accent transition-colors mt-1",title:"Docs",children:e.jsx(F,{className:"w-4 h-4",strokeWidth:1.5})})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("div",{className:"flex items-center gap-1.5 mr-2",children:[e.jsx("span",{className:`w-2 h-2 rounded-full ${A}`}),e.jsx("span",{className:"text-xs text-text-secondary capitalize",children:P})]}),e.jsxs("button",{onClick:()=>i(`/agents/${t.id}/edit`),className:"flex items-center gap-1.5 px-4 py-1.5 text-xs rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors",children:[e.jsx(H,{className:"w-3 h-3"})," Edit"]}),t.status!=="active"&&e.jsxs("button",{onClick:()=>m.mutate({id:t.id,status:"active"}),className:"flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md text-emerald-400 hover:bg-emerald-600/10 transition-colors",children:[e.jsx(G,{className:"w-3 h-3"})," Activate"]}),t.status==="active"&&e.jsxs("button",{onClick:q,className:"flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md text-text-tertiary hover:text-text-primary hover:bg-surface-hover transition-colors",children:[e.jsx(J,{className:"w-3 h-3"})," Pause"]}),e.jsxs("button",{onClick:T,className:"flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md text-red-400/60 hover:text-red-400 hover:bg-red-600/10 transition-colors",children:[e.jsx(O,{className:"w-3 h-3"})," Delete"]})]})]}),t.description&&e.jsx("div",{className:"border-l-2 border-accent/30 pl-4 py-1 mb-10",children:e.jsx("p",{className:"text-[13px] text-text-secondary italic leading-relaxed",children:t.description})}),(t.goals||t.rules)&&e.jsxs("div",{className:"mb-10",children:[e.jsx(u,{icon:Q,color:"text-rose-400",children:"Motivation"}),e.jsxs("div",{className:"grid grid-cols-2 gap-x-14 bg-surface-sunken/20 rounded-lg px-5 py-4",children:[t.goals&&e.jsxs("div",{children:[e.jsx("p",{className:"text-[9px] text-text-quaternary uppercase tracking-widest mb-1.5",children:"Goals"}),e.jsx("p",{className:"text-[13px] text-text-primary leading-relaxed",children:t.goals})]}),t.rules&&e.jsxs("div",{children:[e.jsx("p",{className:"text-[9px] text-text-quaternary uppercase tracking-widest mb-1.5",children:"Rules"}),e.jsx("p",{className:"text-[13px] text-text-primary leading-relaxed",children:t.rules})]})]})]}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-3 gap-x-14 gap-y-10",children:[e.jsxs("div",{children:[e.jsxs(u,{icon:_,color:"text-cyan-400",children:["Subscriptions (",n.length,")"]}),n.length===0?e.jsx(j,{text:"No event subscriptions"}):e.jsx("div",{className:"divide-y divide-surface-border/30",children:n.map(s=>e.jsxs("div",{className:"flex items-center py-2",children:[e.jsx("div",{className:"flex-1 min-w-0",children:e.jsx(E,{topic:s.topic})}),e.jsxs("div",{className:"flex items-center gap-1.5 shrink-0",children:[e.jsx("span",{className:"text-text-quaternary text-[10px]",children:"→"}),e.jsx(N,{type:s.reaction_type==="capability"?s.tool_name:s.workflow_type||s.reaction_type,variant:s.reaction_type==="pipeline"?"pipeline":s.reaction_type==="capability"?"capability":"durable"})]})]},s.id))})]}),e.jsxs("div",{children:[e.jsxs(u,{icon:X,color:"text-amber-400",children:["Schedules (",o,")"]}),l!=null&&l.length?e.jsx("div",{className:"divide-y divide-surface-border/30",children:l.map((s,B)=>e.jsxs("div",{className:"flex items-center py-2",children:[e.jsx("div",{className:"flex-1 min-w-0",children:e.jsx(S,{cron:s.cron})}),e.jsxs("div",{className:"flex items-center gap-1.5 shrink-0",children:[e.jsx("span",{className:"text-text-quaternary text-[10px]",children:"→"}),e.jsx(N,{type:s.workflow_type||"workflow"})]})]},B))}):v?e.jsxs("div",{className:"flex items-center py-1",children:[e.jsx("div",{className:"flex-1 min-w-0",children:e.jsx(S,{cron:v})}),t.workflow_type&&e.jsxs("div",{className:"flex items-center gap-1.5 shrink-0",children:[e.jsx("span",{className:"text-text-quaternary text-[10px]",children:"→"}),e.jsx(N,{type:t.workflow_type})]})]}):e.jsx(j,{text:"No schedules configured"})]}),e.jsxs("div",{className:"space-y-10",children:[e.jsxs("div",{children:[e.jsx(u,{icon:Y,color:"text-emerald-400",children:"Knowledge"}),t.knowledge_domain?e.jsxs("button",{onClick:()=>i(`/knowledge?domain=${t.knowledge_domain}`),className:"group text-left flex items-center gap-3",children:[e.jsx("span",{className:"text-sm font-mono text-text-primary group-hover:text-accent transition-colors",children:t.knowledge_domain}),e.jsxs("span",{className:"text-[10px] text-text-quaternary",children:[(($=(C=t.stats)==null?void 0:C.knowledge_count)==null?void 0:$.toLocaleString())??0," entries"]}),e.jsx(V,{className:"w-3 h-3 text-accent opacity-0 group-hover:opacity-100 transition-opacity"})]}):e.jsx(j,{text:"No knowledge domain"})]}),e.jsxs("div",{children:[e.jsx(u,{icon:_,color:"text-cyan-400",actions:e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:`w-1.5 h-1.5 rounded-full transition-colors duration-500 ${f?"bg-emerald-400":"bg-zinc-600"}`}),e.jsx("span",{className:"text-[10px] text-text-quaternary",children:"live"})]}),children:"Activity"}),p.length===0?e.jsx(j,{text:"Events appear here as the agent runs"}):e.jsx("div",{className:"space-y-1.5",children:p.map(s=>e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-0.5",children:[e.jsx("span",{className:"text-[11px] text-text-primary font-mono truncate flex-1",children:s.label||"—"}),e.jsx("span",{className:"text-[10px] text-text-quaternary shrink-0 ml-2",children:te(s.timestamp)})]}),e.jsx(E,{topic:s.type})]},s.id))})]})]})]})]})}export{me as AgentDetailPage};
|
|
4
|
-
//# sourceMappingURL=AgentDetailPage-C-2iSaDs.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AgentDetailPage-C-2iSaDs.js","sources":["../../src/pages/agents/AgentDetailPage.tsx"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport {\n Bot, Play, Pause, Trash2, ArrowRight, Pencil, BookOpen,\n Radio, Clock, Brain, Compass,\n} from 'lucide-react';\nimport { useAgent, useUpdateAgent, useDeleteAgent } from '../../api/agents';\nimport { useSettings } from '../../api/settings';\nimport { useAgentSubscriptions } from '../../api/agent-subscriptions';\nimport { useAgentEvents } from '../../hooks/useEventHooks';\nimport { useEventSubscription } from '../../hooks/useEventContext';\nimport { NATS_SUBJECT_PREFIX } from '../../lib/nats/config';\nimport { EventTopicPill } from '../../components/common/display/EventTopicPill';\nimport { CronLabel } from '../../components/common/display/CronLabel';\nimport { WorkflowPill } from '../../components/common/display/WorkflowPill';\n\n// ── Helpers ─────────────────────────────────────────────────────────────────\n\nfunction formatTime(iso: string): string {\n return new Date(iso).toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nfunction SectionHeader({ icon: Icon, color, children, actions }: { icon: React.ElementType; color: string; children: React.ReactNode; actions?: React.ReactNode }) {\n return (\n <div className=\"flex items-center justify-between mb-3 pb-2 border-b border-surface-border\">\n <div className=\"flex items-center gap-2\">\n <Icon className={`w-4 h-4 ${color}`} strokeWidth={1.5} />\n <h2 className=\"text-xs font-semibold uppercase tracking-widest text-accent/80\">{children}</h2>\n </div>\n {actions}\n </div>\n );\n}\n\nfunction EmptyHint({ text }: { text: string }) {\n return <p className=\"text-[11px] text-text-quaternary py-2\">{text}</p>;\n}\n\n// ── Live feed ───────────────────────────────────────────────────────────────\n\ninterface FeedEvent { id: number; type: string; timestamp: string; label: string; }\nlet feedCounter = 0;\n\nfunction useAgentFeed(agentName?: string) {\n const [events, setEvents] = useState<FeedEvent[]>([]);\n const [pulse, setPulse] = useState(false);\n const handler = useCallback((event: any) => {\n if (event.type?.startsWith('mesh.')) return;\n const label = event.activityName || event.data?.domain || event.workflowId?.slice(0, 16) || '';\n setEvents((prev) => [{ id: ++feedCounter, type: event.type, timestamp: event.timestamp, label }, ...prev].slice(0, 10));\n setPulse(true);\n setTimeout(() => setPulse(false), 2000);\n }, []);\n useEventSubscription(\n agentName ? `${NATS_SUBJECT_PREFIX}.system.agent.${agentName}.>` : '',\n handler,\n );\n return { events, pulse };\n}\n\n// ── Page ─────────────────────────────────────────────────────────────────────\n\nexport function AgentDetailPage() {\n const { id } = useParams<{ id: string }>();\n const navigate = useNavigate();\n const { data: settings } = useSettings();\n const aiEnabled = !!settings?.ai?.enabled;\n const label = aiEnabled ? 'Agent' : 'Automation';\n const { data: agent, isLoading } = useAgent(id ?? null);\n const { data: subsData } = useAgentSubscriptions(id ?? null);\n const updateMutation = useUpdateAgent();\n const deleteMutation = useDeleteAgent();\n const { events: liveEvents, pulse } = useAgentFeed(id);\n useAgentEvents();\n\n if (isLoading) {\n return <div className=\"animate-pulse space-y-4\"><div className=\"h-8 bg-surface-sunken rounded w-48\" /><div className=\"h-40 bg-surface-sunken rounded\" /></div>;\n }\n\n if (!agent) {\n return (\n <div className=\"flex flex-col items-center justify-center py-20 text-center\">\n <Bot className=\"w-12 h-12 text-text-quaternary mb-4\" strokeWidth={1} />\n <h2 className=\"text-lg font-medium text-text-primary mb-2\">{label} not found</h2>\n <button onClick={() => navigate('/agents')} className=\"text-sm text-accent hover:text-accent-hover transition-colors\">Back to {label.toLowerCase()}s</button>\n </div>\n );\n }\n\n const statusDot = agent.status === 'active' ? 'bg-emerald-400' : agent.status === 'paused' ? 'bg-amber-400' : agent.status === 'error' ? 'bg-red-400' : 'bg-zinc-500';\n const subs = subsData?.subscriptions ?? [];\n const statusLabel = agent.status === 'active' ? 'Active' : agent.status === 'paused' ? 'Paused' : agent.status === 'error' ? 'Error' : 'Inactive';\n const schedules = (agent.behaviors as any)?.schedules as any[] | undefined;\n const legacyCron = agent.behaviors?.cron;\n const schedCount = schedules?.length || (legacyCron ? 1 : 0);\n\n const handlePause = () => {\n const msg = [\n `Pause \"${agent.id}\"?`,\n '',\n 'This will:',\n subs.length > 0 ? `• Stop ${subs.length} event subscription${subs.length !== 1 ? 's' : ''}` : null,\n schedCount > 0 ? `• Stop ${schedCount} schedule${schedCount !== 1 ? 's' : ''}` : null,\n '',\n 'Knowledge and workflow history are preserved. You can reactivate anytime.',\n ].filter(Boolean).join('\\n');\n if (confirm(msg)) updateMutation.mutate({ id: agent.id, status: 'paused' as any });\n };\n\n const handleDelete = () => {\n const msg = [\n `Delete \"${agent.id}\"?`,\n '',\n 'This permanently removes:',\n '• The agent configuration',\n subs.length > 0 ? `• ${subs.length} event subscription${subs.length !== 1 ? 's' : ''}` : null,\n schedCount > 0 ? `• ${schedCount} schedule${schedCount !== 1 ? 's' : ''}` : null,\n '',\n 'Knowledge entries and workflow history are preserved.',\n ].filter(Boolean).join('\\n');\n if (confirm(msg)) deleteMutation.mutate(agent.id, { onSuccess: () => navigate('/agents') });\n };\n\n return (\n <div>\n {/* ── Hero ──────────────────────────────────────────────────────────── */}\n <div className=\"flex items-start justify-between mb-3\">\n <div className=\"flex items-center gap-2\">\n <h1 className=\"text-3xl font-light text-text-primary\">{label}: {agent.id}</h1>\n <button onClick={() => { window.location.hash = '#docs:agents.md'; }} className=\"text-text-quaternary hover:text-accent transition-colors mt-1\" title=\"Docs\">\n <BookOpen className=\"w-4 h-4\" strokeWidth={1.5} />\n </button>\n </div>\n <div className=\"flex items-center gap-3\">\n <div className=\"flex items-center gap-1.5 mr-2\">\n <span className={`w-2 h-2 rounded-full ${statusDot}`} />\n <span className=\"text-xs text-text-secondary capitalize\">{statusLabel}</span>\n </div>\n <button onClick={() => navigate(`/agents/${agent.id}/edit`)} className=\"flex items-center gap-1.5 px-4 py-1.5 text-xs rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors\">\n <Pencil className=\"w-3 h-3\" /> Edit\n </button>\n {agent.status !== 'active' && (\n <button onClick={() => updateMutation.mutate({ id: agent.id, status: 'active' as any })} className=\"flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md text-emerald-400 hover:bg-emerald-600/10 transition-colors\">\n <Play className=\"w-3 h-3\" /> Activate\n </button>\n )}\n {agent.status === 'active' && (\n <button onClick={handlePause} className=\"flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md text-text-tertiary hover:text-text-primary hover:bg-surface-hover transition-colors\">\n <Pause className=\"w-3 h-3\" /> Pause\n </button>\n )}\n <button onClick={handleDelete} className=\"flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md text-red-400/60 hover:text-red-400 hover:bg-red-600/10 transition-colors\">\n <Trash2 className=\"w-3 h-3\" /> Delete\n </button>\n </div>\n </div>\n\n {/* Description callout */}\n {agent.description && (\n <div className=\"border-l-2 border-accent/30 pl-4 py-1 mb-10\">\n <p className=\"text-[13px] text-text-secondary italic leading-relaxed\">{agent.description}</p>\n </div>\n )}\n\n {/* Motivation */}\n {(agent.goals || agent.rules) && (\n <div className=\"mb-10\">\n <SectionHeader icon={Compass} color=\"text-rose-400\">Motivation</SectionHeader>\n <div className=\"grid grid-cols-2 gap-x-14 bg-surface-sunken/20 rounded-lg px-5 py-4\">\n {agent.goals && (\n <div>\n <p className=\"text-[9px] text-text-quaternary uppercase tracking-widest mb-1.5\">Goals</p>\n <p className=\"text-[13px] text-text-primary leading-relaxed\">{agent.goals}</p>\n </div>\n )}\n {agent.rules && (\n <div>\n <p className=\"text-[9px] text-text-quaternary uppercase tracking-widest mb-1.5\">Rules</p>\n <p className=\"text-[13px] text-text-primary leading-relaxed\">{agent.rules}</p>\n </div>\n )}\n </div>\n </div>\n )}\n\n {/* ── 3-column grid ─────────────────────────────────────────────────── */}\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-x-14 gap-y-10\">\n\n {/* Col 1: Subscriptions */}\n <div>\n <SectionHeader icon={Radio} color=\"text-cyan-400\">\n Subscriptions ({subs.length})\n </SectionHeader>\n {subs.length === 0 ? (\n <EmptyHint text=\"No event subscriptions\" />\n ) : (\n <div className=\"divide-y divide-surface-border/30\">\n {subs.map((sub: any) => (\n <div key={sub.id} className=\"flex items-center py-2\">\n <div className=\"flex-1 min-w-0\"><EventTopicPill topic={sub.topic} /></div>\n <div className=\"flex items-center gap-1.5 shrink-0\">\n <span className=\"text-text-quaternary text-[10px]\">→</span>\n <WorkflowPill\n type={sub.reaction_type === 'capability' ? sub.tool_name : sub.workflow_type || sub.reaction_type}\n variant={sub.reaction_type === 'pipeline' ? 'pipeline' : sub.reaction_type === 'capability' ? 'capability' : 'durable'}\n />\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Col 2: Schedules */}\n <div>\n <SectionHeader icon={Clock} color=\"text-amber-400\">Schedules ({schedCount})</SectionHeader>\n {schedules?.length ? (\n <div className=\"divide-y divide-surface-border/30\">\n {schedules.map((s: any, i: number) => (\n <div key={i} className=\"flex items-center py-2\">\n <div className=\"flex-1 min-w-0\"><CronLabel cron={s.cron} /></div>\n <div className=\"flex items-center gap-1.5 shrink-0\"><span className=\"text-text-quaternary text-[10px]\">→</span><WorkflowPill type={s.workflow_type || 'workflow'} /></div>\n </div>\n ))}\n </div>\n ) : legacyCron ? (\n <div className=\"flex items-center py-1\">\n <div className=\"flex-1 min-w-0\"><CronLabel cron={legacyCron} /></div>\n {agent.workflow_type && <div className=\"flex items-center gap-1.5 shrink-0\"><span className=\"text-text-quaternary text-[10px]\">→</span><WorkflowPill type={agent.workflow_type} /></div>}\n </div>\n ) : (\n <EmptyHint text=\"No schedules configured\" />\n )}\n </div>\n\n {/* Col 3: Knowledge + Activity */}\n <div className=\"space-y-10\">\n <div>\n <SectionHeader icon={Brain} color=\"text-emerald-400\">Knowledge</SectionHeader>\n {agent.knowledge_domain ? (\n <button onClick={() => navigate(`/knowledge?domain=${agent.knowledge_domain}`)} className=\"group text-left flex items-center gap-3\">\n <span className=\"text-sm font-mono text-text-primary group-hover:text-accent transition-colors\">{agent.knowledge_domain}</span>\n <span className=\"text-[10px] text-text-quaternary\">{agent.stats?.knowledge_count?.toLocaleString() ?? 0} entries</span>\n <ArrowRight className=\"w-3 h-3 text-accent opacity-0 group-hover:opacity-100 transition-opacity\" />\n </button>\n ) : (\n <EmptyHint text=\"No knowledge domain\" />\n )}\n </div>\n\n <div>\n <SectionHeader icon={Radio} color=\"text-cyan-400\"\n actions={\n <div className=\"flex items-center gap-1.5\">\n <span className={`w-1.5 h-1.5 rounded-full transition-colors duration-500 ${pulse ? 'bg-emerald-400' : 'bg-zinc-600'}`} />\n <span className=\"text-[10px] text-text-quaternary\">live</span>\n </div>\n }\n >\n Activity\n </SectionHeader>\n {liveEvents.length === 0 ? (\n <EmptyHint text=\"Events appear here as the agent runs\" />\n ) : (\n <div className=\"space-y-1.5\">\n {liveEvents.map((ev) => (\n <div key={ev.id}>\n <div className=\"flex items-center justify-between mb-0.5\">\n <span className=\"text-[11px] text-text-primary font-mono truncate flex-1\">{ev.label || '—'}</span>\n <span className=\"text-[10px] text-text-quaternary shrink-0 ml-2\">{formatTime(ev.timestamp)}</span>\n </div>\n <EventTopicPill topic={ev.type} />\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"names":["formatTime","iso","SectionHeader","Icon","color","children","actions","jsxs","jsx","EmptyHint","text","feedCounter","useAgentFeed","agentName","events","setEvents","useState","pulse","setPulse","handler","useCallback","event","_a","label","_b","_c","prev","useEventSubscription","NATS_SUBJECT_PREFIX","AgentDetailPage","id","useParams","navigate","useNavigate","settings","useSettings","agent","isLoading","useAgent","subsData","useAgentSubscriptions","updateMutation","useUpdateAgent","deleteMutation","useDeleteAgent","liveEvents","useAgentEvents","Bot","statusDot","subs","statusLabel","schedules","legacyCron","schedCount","handlePause","msg","handleDelete","BookOpen","Pencil","Play","Pause","Trash2","Compass","Radio","sub","EventTopicPill","WorkflowPill","Clock","i","CronLabel","Brain","_e","_d","ArrowRight","ev"],"mappings":"ueAkBA,SAASA,GAAWC,EAAqB,CACvC,OAAO,IAAI,KAAKA,CAAG,EAAE,mBAAmB,QAAS,CAAE,OAAQ,GAAO,KAAM,UAAW,OAAQ,UAAW,OAAQ,UAAW,CAC3H,CAEA,SAASC,EAAc,CAAE,KAAMC,EAAM,MAAAC,EAAO,SAAAC,EAAU,QAAAC,GAA6G,CACjK,OACEC,EAAAA,KAAC,MAAA,CAAI,UAAU,6EACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAC,MAACL,GAAK,UAAW,WAAWC,CAAK,GAAI,YAAa,IAAK,EACvDI,EAAAA,IAAC,KAAA,CAAG,UAAU,iEAAkE,SAAAH,CAAA,CAAS,CAAA,EAC3F,EACCC,CAAA,EACH,CAEJ,CAEA,SAASG,EAAU,CAAE,KAAAC,GAA0B,CAC7C,OAAOF,EAAAA,IAAC,IAAA,CAAE,UAAU,wCAAyC,SAAAE,EAAK,CACpE,CAKA,IAAIC,GAAc,EAElB,SAASC,GAAaC,EAAoB,CACxC,KAAM,CAACC,EAAQC,CAAS,EAAIC,EAAAA,SAAsB,CAAA,CAAE,EAC9C,CAACC,EAAOC,CAAQ,EAAIF,EAAAA,SAAS,EAAK,EAClCG,EAAUC,cAAaC,GAAe,WAC1C,IAAIC,EAAAD,EAAM,OAAN,MAAAC,EAAY,WAAW,SAAU,OACrC,MAAMC,EAAQF,EAAM,gBAAgBG,EAAAH,EAAM,OAAN,YAAAG,EAAY,WAAUC,EAAAJ,EAAM,aAAN,YAAAI,EAAkB,MAAM,EAAG,MAAO,GAC5FV,EAAWW,GAAS,CAAC,CAAE,GAAI,EAAEf,GAAa,KAAMU,EAAM,KAAM,UAAWA,EAAM,UAAW,MAAAE,GAAS,GAAGG,CAAI,EAAE,MAAM,EAAG,EAAE,CAAC,EACtHR,EAAS,EAAI,EACb,WAAW,IAAMA,EAAS,EAAK,EAAG,GAAI,CACxC,EAAG,CAAA,CAAE,EACL,OAAAS,EACEd,EAAY,GAAGe,CAAmB,iBAAiBf,CAAS,KAAO,GACnEM,CAAA,EAEK,CAAE,OAAAL,EAAQ,MAAAG,CAAA,CACnB,CAIO,SAASY,IAAkB,eAChC,KAAM,CAAE,GAAAC,CAAA,EAAOC,EAAA,EACTC,EAAWC,GAAA,EACX,CAAE,KAAMC,CAAA,EAAaC,EAAA,EAErBZ,EADY,CAAC,GAACD,EAAAY,GAAA,YAAAA,EAAU,KAAV,MAAAZ,EAAc,SACR,QAAU,aAC9B,CAAE,KAAMc,EAAO,UAAAC,GAAcC,EAASR,GAAM,IAAI,EAChD,CAAE,KAAMS,CAAA,EAAaC,EAAsBV,GAAM,IAAI,EACrDW,EAAiBC,EAAA,EACjBC,EAAiBC,EAAA,EACjB,CAAE,OAAQC,EAAY,MAAA5B,CAAA,EAAUL,GAAakB,CAAE,EAGrD,GAFAgB,EAAA,EAEIT,EACF,OAAO9B,EAAAA,KAAC,MAAA,CAAI,UAAU,0BAA0B,SAAA,CAAAC,EAAAA,IAAC,MAAA,CAAI,UAAU,oCAAA,CAAqC,EAAEA,EAAAA,IAAC,MAAA,CAAI,UAAU,gCAAA,CAAiC,CAAA,EAAE,EAG1J,GAAI,CAAC4B,EACH,OACE7B,EAAAA,KAAC,MAAA,CAAI,UAAU,8DACb,SAAA,CAAAC,EAAAA,IAACuC,EAAA,CAAI,UAAU,sCAAsC,YAAa,EAAG,EACrExC,EAAAA,KAAC,KAAA,CAAG,UAAU,6CAA8C,SAAA,CAAAgB,EAAM,YAAA,EAAU,EAC5EhB,OAAC,UAAO,QAAS,IAAMyB,EAAS,SAAS,EAAG,UAAU,gEAAgE,SAAA,CAAA,WAAST,EAAM,YAAA,EAAc,GAAA,CAAA,CAAC,CAAA,EACtJ,EAIJ,MAAMyB,EAAYZ,EAAM,SAAW,SAAW,iBAAmBA,EAAM,SAAW,SAAW,eAAiBA,EAAM,SAAW,QAAU,aAAe,cAClJa,GAAOV,GAAA,YAAAA,EAAU,gBAAiB,CAAA,EAClCW,EAAcd,EAAM,SAAW,SAAW,SAAWA,EAAM,SAAW,SAAW,SAAWA,EAAM,SAAW,QAAU,QAAU,WACjIe,GAAa3B,EAAAY,EAAM,YAAN,YAAAZ,EAAyB,UACtC4B,GAAa3B,EAAAW,EAAM,YAAN,YAAAX,EAAiB,KAC9B4B,GAAaF,GAAA,YAAAA,EAAW,UAAWC,EAAa,EAAI,GAEpDE,EAAc,IAAM,CACxB,MAAMC,EAAM,CACV,UAAUnB,EAAM,EAAE,KAClB,GACA,aACAa,EAAK,OAAS,EAAI,UAAUA,EAAK,MAAM,sBAAsBA,EAAK,SAAW,EAAI,IAAM,EAAE,GAAK,KAC9FI,EAAa,EAAI,UAAUA,CAAU,YAAYA,IAAe,EAAI,IAAM,EAAE,GAAK,KACjF,GACA,2EAAA,EACA,OAAO,OAAO,EAAE,KAAK;AAAA,CAAI,EACvB,QAAQE,CAAG,GAAGd,EAAe,OAAO,CAAE,GAAIL,EAAM,GAAI,OAAQ,QAAA,CAAiB,CACnF,EAEMoB,EAAe,IAAM,CACzB,MAAMD,EAAM,CACV,WAAWnB,EAAM,EAAE,KACnB,GACA,4BACA,4BACAa,EAAK,OAAS,EAAI,KAAKA,EAAK,MAAM,sBAAsBA,EAAK,SAAW,EAAI,IAAM,EAAE,GAAK,KACzFI,EAAa,EAAI,KAAKA,CAAU,YAAYA,IAAe,EAAI,IAAM,EAAE,GAAK,KAC5E,GACA,uDAAA,EACA,OAAO,OAAO,EAAE,KAAK;AAAA,CAAI,EACvB,QAAQE,CAAG,GAAGZ,EAAe,OAAOP,EAAM,GAAI,CAAE,UAAW,IAAMJ,EAAS,SAAS,EAAG,CAC5F,EAEA,cACG,MAAA,CAEC,SAAA,CAAAzB,EAAAA,KAAC,MAAA,CAAI,UAAU,wCACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAA,EAAAA,KAAC,KAAA,CAAG,UAAU,wCAAyC,SAAA,CAAAgB,EAAM,KAAGa,EAAM,EAAA,EAAG,EACzE5B,MAAC,SAAA,CAAO,QAAS,IAAM,CAAE,OAAO,SAAS,KAAO,iBAAmB,EAAG,UAAU,gEAAgE,MAAM,OACpJ,SAAAA,EAAAA,IAACiD,EAAA,CAAS,UAAU,UAAU,YAAa,GAAA,CAAK,CAAA,CAClD,CAAA,EACF,EACAlD,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,iCACb,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAW,wBAAwBwC,CAAS,GAAI,EACtDxC,EAAAA,IAAC,OAAA,CAAK,UAAU,yCAA0C,SAAA0C,CAAA,CAAY,CAAA,EACxE,EACA3C,EAAAA,KAAC,SAAA,CAAO,QAAS,IAAMyB,EAAS,WAAWI,EAAM,EAAE,OAAO,EAAG,UAAU,+HACrE,SAAA,CAAA5B,EAAAA,IAACkD,EAAA,CAAO,UAAU,SAAA,CAAU,EAAE,OAAA,EAChC,EACCtB,EAAM,SAAW,iBACf,SAAA,CAAO,QAAS,IAAMK,EAAe,OAAO,CAAE,GAAIL,EAAM,GAAI,OAAQ,SAAiB,EAAG,UAAU,sHACjG,SAAA,CAAA5B,EAAAA,IAACmD,EAAA,CAAK,UAAU,SAAA,CAAU,EAAE,WAAA,EAC9B,EAEDvB,EAAM,SAAW,UAChB7B,EAAAA,KAAC,UAAO,QAAS+C,EAAa,UAAU,+IACtC,SAAA,CAAA9C,EAAAA,IAACoD,EAAA,CAAM,UAAU,SAAA,CAAU,EAAE,QAAA,EAC/B,EAEFrD,EAAAA,KAAC,SAAA,CAAO,QAASiD,EAAc,UAAU,oIACvC,SAAA,CAAAhD,EAAAA,IAACqD,EAAA,CAAO,UAAU,SAAA,CAAU,EAAE,SAAA,CAAA,CAChC,CAAA,CAAA,CACF,CAAA,EACF,EAGCzB,EAAM,aACL5B,MAAC,MAAA,CAAI,UAAU,8CACb,SAAAA,EAAAA,IAAC,IAAA,CAAE,UAAU,yDAA0D,SAAA4B,EAAM,WAAA,CAAY,EAC3F,GAIAA,EAAM,OAASA,EAAM,QACrB7B,OAAC,MAAA,CAAI,UAAU,QACb,SAAA,CAAAC,MAACN,EAAA,CAAc,KAAM4D,EAAS,MAAM,gBAAgB,SAAA,aAAU,EAC9DvD,EAAAA,KAAC,MAAA,CAAI,UAAU,sEACZ,SAAA,CAAA6B,EAAM,cACJ,MAAA,CACC,SAAA,CAAA5B,EAAAA,IAAC,IAAA,CAAE,UAAU,mEAAmE,SAAA,QAAK,EACrFA,EAAAA,IAAC,IAAA,CAAE,UAAU,gDAAiD,WAAM,KAAA,CAAM,CAAA,EAC5E,EAED4B,EAAM,OACL7B,EAAAA,KAAC,MAAA,CACC,SAAA,CAAAC,EAAAA,IAAC,IAAA,CAAE,UAAU,mEAAmE,SAAA,QAAK,EACrFA,EAAAA,IAAC,IAAA,CAAE,UAAU,gDAAiD,WAAM,KAAA,CAAM,CAAA,CAAA,CAC5E,CAAA,CAAA,CAEJ,CAAA,EACF,EAIFD,EAAAA,KAAC,MAAA,CAAI,UAAU,oDAGb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAA,EAAAA,KAACL,EAAA,CAAc,KAAM6D,EAAO,MAAM,gBAAgB,SAAA,CAAA,kBAChCd,EAAK,OAAO,GAAA,EAC9B,EACCA,EAAK,SAAW,QACdxC,EAAA,CAAU,KAAK,yBAAyB,EAEzCD,EAAAA,IAAC,OAAI,UAAU,oCACZ,WAAK,IAAKwD,GACTzD,EAAAA,KAAC,MAAA,CAAiB,UAAU,yBAC1B,SAAA,CAAAC,EAAAA,IAAC,MAAA,CAAI,UAAU,iBAAiB,SAAAA,EAAAA,IAACyD,GAAe,MAAOD,EAAI,MAAO,CAAA,CAAE,EACpEzD,EAAAA,KAAC,MAAA,CAAI,UAAU,qCACb,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,mCAAmC,SAAA,IAAC,EACpDA,EAAAA,IAAC0D,EAAA,CACC,KAAMF,EAAI,gBAAkB,aAAeA,EAAI,UAAYA,EAAI,eAAiBA,EAAI,cACpF,QAASA,EAAI,gBAAkB,WAAa,WAAaA,EAAI,gBAAkB,aAAe,aAAe,SAAA,CAAA,CAC/G,CAAA,CACF,CAAA,GARQA,EAAI,EASd,CACD,CAAA,CACH,CAAA,EAEJ,SAGC,MAAA,CACC,SAAA,CAAAzD,EAAAA,KAACL,EAAA,CAAc,KAAMiE,EAAO,MAAM,iBAAiB,SAAA,CAAA,cAAYd,EAAW,GAAA,EAAC,EAC1EF,GAAA,MAAAA,EAAW,OACV3C,MAAC,MAAA,CAAI,UAAU,oCACZ,SAAA2C,EAAU,IAAI,CAAC,EAAQiB,IACtB7D,EAAAA,KAAC,MAAA,CAAY,UAAU,yBACrB,SAAA,CAAAC,EAAAA,IAAC,MAAA,CAAI,UAAU,iBAAiB,SAAAA,EAAAA,IAAC6D,GAAU,KAAM,EAAE,KAAM,CAAA,CAAE,EAC3D9D,EAAAA,KAAC,MAAA,CAAI,UAAU,qCAAqC,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,mCAAmC,SAAA,IAAC,EAAOA,EAAAA,IAAC0D,EAAA,CAAa,KAAM,EAAE,eAAiB,UAAA,CAAY,CAAA,CAAA,CAAE,CAAA,CAAA,EAF5JE,CAGV,CACD,CAAA,CACH,EACEhB,EACF7C,OAAC,MAAA,CAAI,UAAU,yBACb,SAAA,CAAAC,EAAAA,IAAC,OAAI,UAAU,iBAAiB,eAAC6D,EAAA,CAAU,KAAMjB,EAAY,CAAA,CAAE,EAC9DhB,EAAM,eAAiB7B,OAAC,MAAA,CAAI,UAAU,qCAAqC,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,mCAAmC,SAAA,IAAC,EAAOA,EAAAA,IAAC0D,EAAA,CAAa,KAAM9B,EAAM,aAAA,CAAe,CAAA,CAAA,CAAE,CAAA,CAAA,CACpL,EAEA5B,EAAAA,IAACC,EAAA,CAAU,KAAK,yBAAA,CAA0B,CAAA,EAE9C,EAGAF,EAAAA,KAAC,MAAA,CAAI,UAAU,aACb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAC,MAACN,EAAA,CAAc,KAAMoE,EAAO,MAAM,mBAAmB,SAAA,YAAS,EAC7DlC,EAAM,iBACL7B,EAAAA,KAAC,SAAA,CAAO,QAAS,IAAMyB,EAAS,qBAAqBI,EAAM,gBAAgB,EAAE,EAAG,UAAU,0CACxF,SAAA,CAAA5B,EAAAA,IAAC,OAAA,CAAK,UAAU,gFAAiF,SAAA4B,EAAM,iBAAiB,EACxH7B,EAAAA,KAAC,OAAA,CAAK,UAAU,mCAAoC,SAAA,GAAAgE,GAAAC,EAAApC,EAAM,QAAN,YAAAoC,EAAa,kBAAb,YAAAD,EAA8B,mBAAoB,EAAE,UAAA,EAAQ,EAChH/D,EAAAA,IAACiE,EAAA,CAAW,UAAU,0EAAA,CAA2E,CAAA,CAAA,CACnG,EAEAjE,EAAAA,IAACC,EAAA,CAAU,KAAK,qBAAA,CAAsB,CAAA,EAE1C,SAEC,MAAA,CACC,SAAA,CAAAD,EAAAA,IAACN,EAAA,CAAc,KAAM6D,EAAO,MAAM,gBAChC,QACExD,EAAAA,KAAC,MAAA,CAAI,UAAU,4BACb,SAAA,CAAAC,MAAC,QAAK,UAAW,2DAA2DS,EAAQ,iBAAmB,aAAa,GAAI,EACxHT,EAAAA,IAAC,OAAA,CAAK,UAAU,mCAAmC,SAAA,MAAA,CAAI,CAAA,EACzD,EAEH,SAAA,UAAA,CAAA,EAGAqC,EAAW,SAAW,EACrBrC,MAACC,EAAA,CAAU,KAAK,uCAAuC,EAEvDD,MAAC,MAAA,CAAI,UAAU,cACZ,SAAAqC,EAAW,IAAK6B,UACd,MAAA,CACC,SAAA,CAAAnE,EAAAA,KAAC,MAAA,CAAI,UAAU,2CACb,SAAA,CAAAC,MAAC,OAAA,CAAK,UAAU,0DAA2D,SAAAkE,EAAG,OAAS,IAAI,QAC1F,OAAA,CAAK,UAAU,iDAAkD,SAAA1E,GAAW0E,EAAG,SAAS,CAAA,CAAE,CAAA,EAC7F,EACAlE,EAAAA,IAACyD,EAAA,CAAe,MAAOS,EAAG,IAAA,CAAM,CAAA,GALxBA,EAAG,EAMb,CACD,CAAA,CACH,CAAA,CAAA,CAEJ,CAAA,CAAA,CACF,CAAA,CAAA,CACF,CAAA,EACF,CAEJ"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{j as e}from"./vendor-query-B2UbickB.js";import{u as h}from"./agents-JE4aL07D.js";import{u as f,c as b}from"./index-DPJW96d2.js";import{i as j}from"./useEventHooks-CjygrbYy.js";import{u as v}from"./useFilterParams-x-Dg0Vgz.js";import{D as N}from"./DataTable-D9yuBv0w.js";import{S as y}from"./StickyPagination-BWhFSr2d.js";import{F as P,b as S}from"./FilterBar-Ck4K4rzu.js";import{P as k}from"./PageHeader-Bnt2iQQa.js";import{L as w}from"./ListToolbar-BH9rwQVE.js";import{m as _}from"./vendor-icons-Dj2F0Jrb.js";import{c as A}from"./vendor-react-CXumBFUA.js";import"./EmptyState-BcsfPq9T.js";const $=[{value:"active",label:"Active"},{value:"inactive",label:"Inactive"},{value:"paused",label:"Paused"},{value:"error",label:"Error"}],z=[{key:"name",label:"Agent",render:t=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:`w-1.5 h-1.5 rounded-full shrink-0 ${t.status==="active"?"bg-emerald-400":t.status==="paused"?"bg-amber-400":t.status==="error"?"bg-red-400":"bg-zinc-500"}`}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("span",{className:"text-xs font-medium text-text-primary block",children:t.id}),t.description&&e.jsx("p",{className:"text-[10px] text-text-tertiary truncate",children:t.description})]})]})},{key:"knowledge_domain",label:"Knowledge",render:t=>t.knowledge_domain?e.jsx("span",{className:"text-[10px] font-mono text-text-secondary whitespace-nowrap",children:t.knowledge_domain}):e.jsx("span",{className:"text-text-quaternary",children:"—"}),className:"w-28"},{key:"schedules",label:"Schedules",render:t=>{var o,r;const s=(o=t.behaviors)==null?void 0:o.schedules,a=s!=null&&s.length?s.map(i=>i.cron):(r=t.behaviors)!=null&&r.cron?[t.behaviors.cron]:[];return a.length?e.jsxs("span",{className:"text-[10px] font-mono text-text-secondary whitespace-nowrap",children:[a[0],a.length>1?` +${a.length-1}`:""]}):e.jsx("span",{className:"text-text-quaternary",children:"—"})},className:"w-28"},{key:"subscriptions",label:"Subscriptions",render:t=>{var r;const s=t.subscription_count??0,a=t.sub_topics??[];if(!s)return e.jsx("span",{className:"text-text-quaternary",children:"—"});const o=((r=a[0])==null?void 0:r.replace(/^lt\.events\./,""))??"";return e.jsxs("span",{className:"text-[10px] font-mono text-text-secondary whitespace-nowrap",children:[o,s>1?` +${s-1}`:""]})},className:"w-36"},{key:"last_run_at",label:"Last Run",render:t=>t.last_run_at?e.jsx("span",{className:"whitespace-nowrap",children:e.jsx(b,{date:t.last_run_at})}):e.jsx("span",{className:"text-text-quaternary",children:"—"}),className:"w-32"}];function M(){var u;const t=A(),{data:s}=f(),a=!!((u=s==null?void 0:s.ai)!=null&&u.enabled),o=a?"Agent":"Automation",r=a?"Agents":"Automations";j();const{filters:i,setFilter:p,pagination:n}=v({filters:{status:""}}),{data:l,isLoading:d,refetch:x,isFetching:g}=h({status:i.status||void 0,limit:n.pageSize,offset:n.offset}),m=(l==null?void 0:l.total)??0;return e.jsxs("div",{children:[e.jsx(k,{title:r,docsHash:"#docs:agents.md",actions:e.jsxs("button",{onClick:()=>t("/agents/new"),className:"flex items-center gap-2 px-4 py-2 text-sm rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors",children:[e.jsx(_,{className:"w-4 h-4"})," Create ",o]})}),e.jsx(P,{actions:e.jsx(w,{onRefresh:()=>x(),isFetching:g,apiPath:`/agents?limit=${n.pageSize}&offset=${n.offset}${i.status?`&status=${i.status}`:""}`}),children:e.jsx(S,{label:"Status",value:i.status,onChange:c=>p("status",c),options:$})}),e.jsx(N,{columns:z,data:(l==null?void 0:l.agents)??[],keyFn:c=>c.id,onRowClick:c=>t(`/agents/${c.id}`),isLoading:d,emptyMessage:`No ${r.toLowerCase()} found`}),e.jsx(y,{page:n.page,totalPages:n.totalPages(m),onPageChange:n.setPage,total:m,pageSize:n.pageSize,onPageSizeChange:n.setPageSize})]})}export{M as AgentsPage};
|
|
2
|
-
//# sourceMappingURL=AgentsPage-C3FztFd_.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AgentsPage-C3FztFd_.js","sources":["../../src/pages/agents/AgentsPage.tsx"],"sourcesContent":["import { useNavigate } from 'react-router-dom';\nimport { Plus } from 'lucide-react';\nimport { useAgents, type Agent } from '../../api/agents';\nimport { useSettings } from '../../api/settings';\nimport { useAgentEvents } from '../../hooks/useEventHooks';\nimport { useFilterParams } from '../../hooks/useFilterParams';\nimport { DataTable, type Column } from '../../components/common/data/DataTable';\nimport { StickyPagination } from '../../components/common/data/StickyPagination';\nimport { FilterBar, FilterSelect } from '../../components/common/data/FilterBar';\nimport { PageHeader } from '../../components/common/layout/PageHeader';\nimport { ListToolbar } from '../../components/common/data/ListToolbar';\nimport { DateValue } from '../../components/common/display/DateValue';\n\nconst STATUS_OPTIONS = [\n { value: 'active', label: 'Active' },\n { value: 'inactive', label: 'Inactive' },\n { value: 'paused', label: 'Paused' },\n { value: 'error', label: 'Error' },\n];\n\nconst columns: Column<Agent>[] = [\n {\n key: 'name',\n label: 'Agent',\n render: (row) => (\n <div className=\"flex items-center gap-2\">\n <span className={`w-1.5 h-1.5 rounded-full shrink-0 ${row.status === 'active' ? 'bg-emerald-400' : row.status === 'paused' ? 'bg-amber-400' : row.status === 'error' ? 'bg-red-400' : 'bg-zinc-500'}`} />\n <div className=\"min-w-0\">\n <span className=\"text-xs font-medium text-text-primary block\">{row.id}</span>\n {row.description && <p className=\"text-[10px] text-text-tertiary truncate\">{row.description}</p>}\n </div>\n </div>\n ),\n },\n {\n key: 'knowledge_domain',\n label: 'Knowledge',\n render: (row) => row.knowledge_domain\n ? <span className=\"text-[10px] font-mono text-text-secondary whitespace-nowrap\">{row.knowledge_domain}</span>\n : <span className=\"text-text-quaternary\">—</span>,\n className: 'w-28',\n },\n {\n key: 'schedules',\n label: 'Schedules',\n render: (row) => {\n const scheds = (row.behaviors as any)?.schedules as any[] | undefined;\n const crons = scheds?.length ? scheds.map((s: any) => s.cron) : row.behaviors?.cron ? [row.behaviors.cron] : [];\n if (!crons.length) return <span className=\"text-text-quaternary\">—</span>;\n return <span className=\"text-[10px] font-mono text-text-secondary whitespace-nowrap\">{crons[0]}{crons.length > 1 ? ` +${crons.length - 1}` : ''}</span>;\n },\n className: 'w-28',\n },\n {\n key: 'subscriptions',\n label: 'Subscriptions',\n render: (row) => {\n const count = row.subscription_count ?? 0;\n const topics = row.sub_topics ?? [];\n if (!count) return <span className=\"text-text-quaternary\">—</span>;\n const first = topics[0]?.replace(/^lt\\.events\\./, '') ?? '';\n return <span className=\"text-[10px] font-mono text-text-secondary whitespace-nowrap\">{first}{count > 1 ? ` +${count - 1}` : ''}</span>;\n },\n className: 'w-36',\n },\n {\n key: 'last_run_at',\n label: 'Last Run',\n render: (row) => row.last_run_at\n ? <span className=\"whitespace-nowrap\"><DateValue date={row.last_run_at} /></span>\n : <span className=\"text-text-quaternary\">—</span>,\n className: 'w-32',\n },\n];\n\nexport function AgentsPage() {\n const navigate = useNavigate();\n const { data: settings } = useSettings();\n const aiEnabled = !!settings?.ai?.enabled;\n const label = aiEnabled ? 'Agent' : 'Automation';\n const labelPlural = aiEnabled ? 'Agents' : 'Automations';\n useAgentEvents();\n\n const { filters, setFilter, pagination } = useFilterParams({\n filters: { status: '' },\n });\n\n const { data, isLoading, refetch, isFetching } = useAgents({\n status: filters.status || undefined,\n limit: pagination.pageSize,\n offset: pagination.offset,\n });\n\n const total = data?.total ?? 0;\n\n return (\n <div>\n <PageHeader\n title={labelPlural}\n docsHash=\"#docs:agents.md\"\n actions={\n <button\n onClick={() => navigate('/agents/new')}\n className=\"flex items-center gap-2 px-4 py-2 text-sm rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors\"\n >\n <Plus className=\"w-4 h-4\" /> Create {label}\n </button>\n }\n />\n\n <FilterBar actions={\n <ListToolbar\n onRefresh={() => refetch()}\n isFetching={isFetching}\n apiPath={`/agents?limit=${pagination.pageSize}&offset=${pagination.offset}${filters.status ? `&status=${filters.status}` : ''}`}\n />\n }>\n <FilterSelect\n label=\"Status\"\n value={filters.status}\n onChange={(v) => setFilter('status', v)}\n options={STATUS_OPTIONS}\n />\n </FilterBar>\n\n <DataTable\n columns={columns}\n data={data?.agents ?? []}\n keyFn={(row) => row.id}\n onRowClick={(row) => navigate(`/agents/${row.id}`)}\n isLoading={isLoading}\n emptyMessage={`No ${labelPlural.toLowerCase()} found`}\n />\n\n <StickyPagination\n page={pagination.page}\n totalPages={pagination.totalPages(total)}\n onPageChange={pagination.setPage}\n total={total}\n pageSize={pagination.pageSize}\n onPageSizeChange={pagination.setPageSize}\n />\n </div>\n );\n}\n"],"names":["STATUS_OPTIONS","columns","row","jsxs","jsx","scheds","_a","crons","s","_b","count","topics","first","DateValue","AgentsPage","navigate","useNavigate","settings","useSettings","aiEnabled","label","labelPlural","useAgentEvents","filters","setFilter","pagination","useFilterParams","data","isLoading","refetch","isFetching","useAgents","total","PageHeader","Plus","FilterBar","ListToolbar","FilterSelect","v","DataTable","StickyPagination"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{j as e,a as o}from"./vendor-query-B2UbickB.js";import{j as pe,g as Ce,k as fe,l as be,m as ye,n as je,o as ve,p as ke,q as Se,r as Ne,s as Pe,t as Ae}from"./index-DPJW96d2.js";import{f as we}from"./useEventHooks-CjygrbYy.js";import{u as q,C as K,a as Ee}from"./CustomDurationPicker-Vcmr4LiR.js";import{u as Be}from"./roles-CSpHRRu8.js";import{u as Me}from"./useFilterParams-x-Dg0Vgz.js";import{D as Te}from"./DataTable-D9yuBv0w.js";import{S as Le}from"./StickyPagination-BWhFSr2d.js";import{P as ze}from"./PageHeader-Bnt2iQQa.js";import{P as Fe}from"./constants-BHkpVaqx.js";import{M as D}from"./Modal-CSrxpXeM.js";import{u as Ie}from"./users-DvhHbR0R.js";import{E as Oe,a as $e}from"./escalation-columns-DqTkKbCv.js";import{R as Re,a as _e}from"./RowActions-Dg-Fsm5O.js";import{L as Ue}from"./ListToolbar-BH9rwQVE.js";import{a4 as He}from"./vendor-icons-Dj2F0Jrb.js";import{c as qe}from"./vendor-react-CXumBFUA.js";import"./EmptyState-BcsfPq9T.js";import"./FilterBar-Ck4K4rzu.js";import"./PriorityBadge-DfQY9St9.js";import"./RolePill-DQTT1s9v.js";import"./WorkflowPill-F1oKUzmc.js";import"./TimestampCell-Dsje8GH-.js";import"./escalation-ne7dIaPa.js";const De=t=>t.isPriorityPending||t.isClaimPending||t.isAssignPending||t.isEscalatePending||t.isTriagePending||t.isCancelPending;function Qe(t){const a=De(t),c=q();return e.jsxs("div",{className:"flex flex-wrap items-center gap-3 px-4 py-3 bg-accent/5 border border-accent/20 rounded-lg mb-4",children:[e.jsxs("span",{className:"text-xs font-medium text-accent",children:[t.selectedCount," selected"]}),e.jsx("div",{className:"w-px h-5 bg-surface-border"}),e.jsxs("select",{onChange:s=>{s.target.value&&(t.onSetPriority(parseInt(s.target.value)),s.target.value="")},disabled:a,className:"select text-xs py-1.5",defaultValue:"",children:[e.jsx("option",{value:"",disabled:!0,children:"Priority..."}),Fe.map(s=>e.jsx("option",{value:s.value,children:s.label},s.value))]}),e.jsxs("select",{onChange:s=>{s.target.value&&(t.onClaim(parseInt(s.target.value)),s.target.value="")},disabled:a,className:"select text-xs py-1.5",defaultValue:"",children:[e.jsx("option",{value:"",disabled:!0,children:"Claim for..."}),c.map(s=>e.jsx("option",{value:s.value,children:s.label},s.value))]}),e.jsx("button",{onClick:t.onAssign,disabled:a,className:"btn-secondary text-xs py-1.5",children:t.isAssignPending?"Assigning...":"Assign to..."}),t.availableRoles.length>0&&e.jsxs("select",{onChange:s=>{s.target.value&&(t.onEscalate(s.target.value),s.target.value="")},disabled:a,className:"select text-xs py-1.5",defaultValue:"",children:[e.jsx("option",{value:"",disabled:!0,children:"Escalate to..."}),t.availableRoles.map(s=>e.jsx("option",{value:s,children:s},s))]}),e.jsx("button",{onClick:t.onTriage,disabled:a,className:"btn-secondary text-xs py-1.5",children:t.isTriagePending?"Triaging...":"Triage"}),e.jsx("button",{onClick:t.onCancel,disabled:a,className:"text-xs py-1.5 px-3 rounded-md border border-status-error/40 text-status-error hover:bg-status-error/10 transition-colors disabled:opacity-50",children:t.isCancelPending?"Cancelling...":"Cancel"}),e.jsx("div",{className:"flex-1"}),e.jsx("button",{onClick:t.onClearSelection,className:"text-xs text-text-tertiary hover:text-text-primary transition-colors",children:"Clear"}),a&&e.jsx("span",{className:"text-xs text-text-tertiary animate-pulse",children:"Processing..."})]})}function Ve({open:t,onClose:a,selectedCount:c,selectedRoles:s,onSubmit:m,isPending:x}){const{isSuperAdmin:C}=pe(),u=q(),[i,g]=o.useState("user"),[y,E]=o.useState(null),[j,F]=o.useState(""),[r,h]=o.useState("30"),[R,v]=o.useState(0),_=o.useCallback(l=>v(l),[]),B=!C&&s.length===1?s[0]:void 0,{data:f,isLoading:N}=Ie({role:B,status:"active",limit:200}),M=o.useMemo(()=>{const l=(f==null?void 0:f.users)??[];if(!j.trim())return l;const k=j.toLowerCase();return l.filter(p=>{var P,S;return((P=p.display_name)==null?void 0:P.toLowerCase().includes(k))||((S=p.email)==null?void 0:S.toLowerCase().includes(k))})},[f==null?void 0:f.users,j]),T=()=>{g("user"),E(null),F(""),h("30"),v(0),a()},I=l=>{E(l),g("duration")},L=()=>{g("user")},O=()=>{if(!y)return;const l=r==="custom"?R:parseInt(r);!l||l<=0||m(y.id,l)};return e.jsx(D,{open:t,onClose:T,title:"Assign Escalations",children:e.jsxs("div",{className:"space-y-4",children:[i==="user"&&e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"text-sm text-text-secondary",children:["Select a user to assign"," ",e.jsx("span",{className:"font-medium text-text-primary",children:c})," ","escalation(s) to:"]}),e.jsx("input",{type:"text",value:j,onChange:l=>F(l.target.value),placeholder:"Search by name or email...",className:"input text-xs w-full",autoFocus:!0}),e.jsxs("div",{className:"max-h-60 overflow-y-auto border border-surface-border rounded-lg divide-y divide-surface-border",children:[N&&e.jsx("p",{className:"text-xs text-text-tertiary p-3",children:"Loading users..."}),!N&&M.length===0&&e.jsx("p",{className:"text-xs text-text-tertiary p-3",children:"No users found"}),M.map(l=>e.jsxs("button",{onClick:()=>I(l),className:"w-full text-left px-3 py-2 hover:bg-surface-hover transition-colors",children:[e.jsx("p",{className:"text-xs font-medium text-text-primary",children:l.display_name||l.external_id}),l.email&&e.jsx("p",{className:"text-[10px] text-text-tertiary",children:l.email})]},l.id))]}),e.jsx("div",{className:"flex justify-end pt-2",children:e.jsx("button",{onClick:T,className:"btn-secondary text-xs",children:"Cancel"})})]}),i==="duration"&&y&&e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"text-sm text-text-secondary",children:["Assign to"," ",e.jsx("span",{className:"font-medium text-text-primary",children:y.display_name||y.external_id})," ","for:"]}),e.jsxs("select",{value:r,onChange:l=>{h(l.target.value),v(0)},className:"select w-full text-sm",children:[u.map(l=>e.jsx("option",{value:l.value,children:l.label},l.value)),e.jsx("option",{value:"custom",children:"Other..."})]}),r==="custom"&&e.jsx(K,{onChange:_,autoFocus:!0}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:L,className:"btn-secondary text-xs",children:"Back"}),e.jsx("button",{onClick:O,disabled:x,className:"btn-primary text-xs",children:x?"Assigning...":"Assign"})]})]})]})})}function Ge({open:t,onClose:a,selectedCount:c,onSubmit:s,isPending:m}){const[x,C]=o.useState(""),u=()=>{s(x||void 0)};return e.jsx(D,{open:t,onClose:a,title:"Submit for AI Triage",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("p",{className:"text-sm text-text-secondary",children:["Submit ",e.jsx("span",{className:"font-medium text-text-primary",children:c})," escalation(s) for AI triage? The triage orchestrator will take over resolution."]}),e.jsxs("div",{children:[e.jsxs("label",{className:"text-xs font-medium text-text-secondary block mb-1",children:["Triage hint ",e.jsx("span",{className:"text-text-tertiary",children:"(optional)"})]}),e.jsx("input",{type:"text",value:x,onChange:i=>C(i.target.value),placeholder:"e.g., image_orientation",className:"input text-xs font-mono w-full"}),e.jsx("p",{className:"text-[10px] text-text-tertiary mt-1",children:"Guides the triage workflow on what remediation to apply"})]}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:a,className:"btn-secondary text-xs",children:"Cancel"}),e.jsx("button",{onClick:u,disabled:m,className:"btn-primary text-xs",children:m?"Submitting...":"Submit for Triage"})]})]})})}function w(t,a,c){return s=>{t.mutate(s,{onSuccess:()=>{a(),c==null||c()}})}}function Ye(t){const a=()=>[...t.selectedIds];return{handleSetPriority:i=>{w(t.setPriority,t.clearSelection)({ids:a(),priority:i})},handleBulkClaim:i=>{w(t.bulkClaim,t.clearSelection)({ids:a(),durationMinutes:i})},handleBulkEscalate:i=>{w(t.bulkEscalate,t.clearSelection)({ids:a(),targetRole:i})},handleBulkTriage:i=>{w(t.bulkTriage,t.clearSelection,t.closeTriageModal)({ids:a(),hint:i})},handleBulkAssign:(i,g)=>{w(t.bulkAssign,t.clearSelection,t.closeAssignModal)({ids:a(),targetUserId:i,durationMinutes:g})},handleBulkCancel:()=>{w(t.bulkCancel,t.clearSelection,t.closeCancelModal)({ids:a()})}}}function Je({claimTarget:t,onClose:a,claimDuration:c,onDurationChange:s,claimDurations:m,onCustomClaimChange:x,onClaim:C,isPending:u}){return e.jsx(D,{open:!!t,onClose:a,title:"Claim Escalation",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("p",{className:"text-sm text-text-secondary",children:["Claim ",e.jsx("span",{className:"font-medium text-text-primary",children:t==null?void 0:t.type})," for:"]}),e.jsxs("select",{value:c,onChange:i=>{s(i.target.value)},className:"select w-full text-sm",children:[m.map(i=>e.jsx("option",{value:i.value,children:i.label},i.value)),e.jsx("option",{value:"custom",children:"Other..."})]}),c==="custom"&&e.jsx(K,{onChange:x,autoFocus:!0}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:a,className:"btn-secondary text-xs",children:"Cancel"}),e.jsx("button",{onClick:C,className:"btn-primary text-xs",disabled:u,children:u?"Claiming...":"Claim"})]})]})})}function yt(){we();const t=qe(),{filters:a,setFilter:c,pagination:s,sort:m,setSort:x}=Me({filters:{role:"",type:"",priority:"",status:"available",search:""}}),C=q(),[u,i]=o.useState(null),[g,y]=o.useState("30"),[E,j]=o.useState(0),F=o.useCallback(n=>j(n),[]),[r,h]=o.useState(new Set),[R,v]=o.useState(!1),[_,B]=o.useState(!1),[f,N]=o.useState(!1),M=Ce(),T=fe(),I=be(),L=ye(),O=je(),l=ve(),k=ke(),{data:p}=Be(),{data:P}=Se();o.useEffect(()=>{h(new Set)},[a.role,a.type,a.priority,a.status,s.page,s.pageSize]);const S=a.status||"",z=S==="available",Q=S==="claimed",U=Q?"pending":S==="resolved"?"resolved":S==="cancelled"?"cancelled":void 0,V={role:a.role||void 0,type:a.type||void 0,priority:a.priority?parseInt(a.priority):void 0,limit:s.pageSize,offset:s.offset,sort_by:m.sort_by||"created_at",order:m.order||"desc"},W=Ne({...V,enabled:z}),X=Pe({status:U,claimed:Q||void 0,...V,enabled:!z}),Z=z?W:X,{data:A,isLoading:ee,error:$,refetch:te,isFetching:se}=Z,G=(A==null?void 0:A.escalations)??[],H=(a.search??"").toLowerCase(),b=H?G.filter(n=>{const d=[n.id,n.type,n.subtype,n.description,n.workflow_id,n.origin_id,n.role];return n.metadata&&d.push(...Object.values(n.metadata).map(String)),d.some(J=>J&&String(J).toLowerCase().includes(H))}):G,Y=H?b.length:(A==null?void 0:A.total)??0,{canBulk:ae}=Ae(),ne=o.useMemo(()=>{const n=new Set;for(const d of b)r.has(d.id)&&n.add(d.role);return[...n]},[b,r]),le=o.useCallback(()=>h(new Set),[]),ie=()=>{if(!u)return;const n=g==="custom"?E:parseInt(g);!n||n<=0||M.mutate({id:u.id,durationMinutes:n},{onSuccess:()=>{i(null),t(`/escalations/detail/${u.id}`)}})},{handleSetPriority:oe,handleBulkClaim:re,handleBulkEscalate:ce,handleBulkTriage:de,handleBulkAssign:ue,handleBulkCancel:me}=Ye({selectedIds:r,clearSelection:le,setPriority:T,bulkClaim:I,bulkEscalate:O,bulkTriage:l,bulkAssign:L,bulkCancel:k,closeTriageModal:()=>v(!1),closeAssignModal:()=>B(!1),closeCancelModal:()=>N(!1)}),xe=n=>{const d=new Set(r);d.has(n)?d.delete(n):d.add(n),h(d)},ge=()=>{r.size===b.length?h(new Set):h(new Set(b.map(n=>n.id)))},he=[ae?{key:"select",label:e.jsx("input",{type:"checkbox",checked:b.length>0&&r.size===b.length,onChange:ge,className:"rounded"}),render:n=>e.jsx("input",{type:"checkbox",checked:r.has(n.id),onChange:d=>{d.stopPropagation(),xe(n.id)},onClick:d=>d.stopPropagation(),className:"rounded"}),className:"w-10"}:{key:"spacer",label:"",render:()=>null,className:"w-10"},...Oe,{key:"actions",label:"",render:n=>e.jsx(Re,{children:e.jsx(_e,{icon:He,title:"Claim escalation",onClick:()=>i(n)})}),className:"w-16 text-right"}];return e.jsxs("div",{children:[e.jsx(ze,{title:"Available Escalations",docsHash:"#docs:dashboard.md:all-escalations"}),e.jsx($e,{filters:a,setFilter:c,roles:(p==null?void 0:p.roles)??[],types:(P==null?void 0:P.types)??[],showStatus:!0,actions:e.jsx(Ue,{onRefresh:()=>te(),isFetching:se,apiPath:`/escalations${z?"/available":""}?limit=${s.pageSize}&offset=${s.offset}${U?`&status=${U}`:""}${a.role?`&role=${a.role}`:""}${a.type?`&type=${a.type}`:""}${a.priority?`&priority=${a.priority}`:""}`})}),r.size>0&&e.jsx(Qe,{selectedCount:r.size,onClearSelection:()=>h(new Set),onSetPriority:oe,onClaim:re,onAssign:()=>B(!0),onEscalate:ce,onTriage:()=>v(!0),onCancel:()=>N(!0),isPriorityPending:T.isPending,isClaimPending:I.isPending,isAssignPending:L.isPending,isEscalatePending:O.isPending,isTriagePending:l.isPending,isCancelPending:k.isPending,availableRoles:(p==null?void 0:p.roles)??[]}),$&&e.jsx("div",{className:"mb-4 px-4 py-3 rounded-md bg-status-error/10 border border-status-error/20 text-xs text-status-error",children:$.message==="Session expired"?"Your session has expired. Please log in again.":`Failed to load escalations: ${$.message}`}),e.jsx(Te,{columns:he,data:b,keyFn:n=>n.id,onRowClick:n=>t(`/escalations/detail/${n.id}`,{state:{from:"/escalations/available"}}),isLoading:ee,emptyMessage:$?"Unable to load data":"No available escalations",sort:m,onSort:x}),e.jsx(Le,{page:s.page,totalPages:s.totalPages(Y),onPageChange:s.setPage,total:Y,pageSize:s.pageSize,onPageSizeChange:s.setPageSize}),e.jsx(Je,{claimTarget:u,onClose:()=>i(null),claimDuration:g,onDurationChange:n=>{y(n),j(0)},claimDurations:C,customClaimMinutes:E,onCustomClaimChange:F,onClaim:ie,isPending:M.isPending}),e.jsx(Ge,{open:R,onClose:()=>v(!1),selectedCount:r.size,onSubmit:de,isPending:l.isPending}),e.jsx(Ve,{open:_,onClose:()=>B(!1),selectedCount:r.size,selectedRoles:ne,onSubmit:ue,isPending:L.isPending}),e.jsx(Ee,{open:f,onClose:()=>N(!1),onConfirm:me,selectedCount:r.size,isPending:k.isPending,error:k.error})]})}export{yt as AvailableEscalationsPage};
|
|
2
|
-
//# sourceMappingURL=AvailableEscalationsPage-DIqdBCwe.js.map
|