agent-webui 2.7.1__tar.gz → 2.8.1__tar.gz

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.
Files changed (289) hide show
  1. {agent_webui-2.7.1 → agent_webui-2.8.1}/PKG-INFO +9 -4
  2. {agent_webui-2.7.1 → agent_webui-2.8.1}/README.md +4 -2
  3. agent_webui-2.8.1/agent/agent_webui/__tests__/test_run_identity.py +218 -0
  4. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_security_boundaries.py +1 -1
  5. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_served_operations.py +2 -2
  6. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/api_extensions.py +5 -9
  7. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/apps/markets/router.py +2 -3
  8. agent_webui-2.8.1/agent/agent_webui/auth_policy.py +99 -0
  9. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/contact_delivery.py +1 -1
  10. agent_webui-2.8.1/agent/agent_webui/dist/assets/AdminView-DkoVw_JQ.js +1 -0
  11. agent_webui-2.7.1/agent/agent_webui/dist/assets/AgentLibraryView-CN9epMHd.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/AgentLibraryView-Dw08aoiC.js +1 -1
  12. agent_webui-2.8.1/agent/agent_webui/dist/assets/ArboraReadinessView-Dd-yF6Pc.js +1 -0
  13. agent_webui-2.8.1/agent/agent_webui/dist/assets/AtlasView-Dw_6qT5o.js +5 -0
  14. agent_webui-2.7.1/agent/agent_webui/dist/assets/Availability-Den2CaKK.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/Availability-Ajw5i9OT.js +1 -1
  15. agent_webui-2.8.1/agent/agent_webui/dist/assets/BrokerView-DI5UtgKp.js +1 -0
  16. agent_webui-2.7.1/agent/agent_webui/dist/assets/CatalogueView-B4K-jYbP.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/CatalogueView-DrB6Bt9v.js +1 -1
  17. agent_webui-2.8.1/agent/agent_webui/dist/assets/ChartPage-BFlYluks.js +1 -0
  18. agent_webui-2.7.1/agent/agent_webui/dist/assets/CodeGraphView-CUlMGeog.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/CodeGraphView-DoH8F7vn.js +1 -1
  19. agent_webui-2.7.1/agent/agent_webui/dist/assets/ConfigurationView-QQbmt8FI.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/ConfigurationView-BcWFtUz4.js +1 -1
  20. agent_webui-2.7.1/agent/agent_webui/dist/assets/ConsoleConfirmView-DGgSpeYr.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/ConsoleConfirmView-BBmcpDTh.js +1 -1
  21. agent_webui-2.7.1/agent/agent_webui/dist/assets/ContactPage-DVqe4ojO.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/ContactPage-Rjy-Fzt1.js +1 -1
  22. agent_webui-2.8.1/agent/agent_webui/dist/assets/CypherReplView-DXbPrlX9.js +1 -0
  23. agent_webui-2.8.1/agent/agent_webui/dist/assets/DashboardView-Cj-Dyoz6.js +1 -0
  24. agent_webui-2.8.1/agent/agent_webui/dist/assets/DashboardsView-B7N8NUhC.js +1 -0
  25. agent_webui-2.7.1/agent/agent_webui/dist/assets/DataAnalystView-D2rDgmTE.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/DataAnalystView-BP36t40R.js +1 -1
  26. agent_webui-2.8.1/agent/agent_webui/dist/assets/EcosystemView-DQhFdYI8.js +1 -0
  27. agent_webui-2.8.1/agent/agent_webui/dist/assets/ExploreQueryWorkspace-CQAypB0T.js +1 -0
  28. agent_webui-2.7.1/agent/agent_webui/dist/assets/ExtractionView-SIs5t7-2.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/ExtractionView-zeBq8fuD.js +1 -1
  29. agent_webui-2.8.1/agent/agent_webui/dist/assets/FilesView-Bh3WCxLU.js +1 -0
  30. agent_webui-2.7.1/agent/agent_webui/dist/assets/FleetView-CqZBn2Gb.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/FleetView-DaJBH4yv.js +1 -1
  31. agent_webui-2.7.1/agent/agent_webui/dist/assets/GoalsView-qftV4zVF.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/GoalsView-arsjahLZ.js +1 -1
  32. agent_webui-2.8.1/agent/agent_webui/dist/assets/Graph3DLodView-_3yOQ99X.js +1 -0
  33. agent_webui-2.7.1/agent/agent_webui/dist/assets/Graph3DView-DvrfNH4Y.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/Graph3DView-DCtaQVl1.js +1 -1
  34. agent_webui-2.8.1/agent/agent_webui/dist/assets/GraphCanvas-CSptFCKQ.js +1 -0
  35. agent_webui-2.8.1/agent/agent_webui/dist/assets/GraphView-DZXqwt-s.js +1 -0
  36. agent_webui-2.7.1/agent/agent_webui/dist/assets/ImportExportModal-3aJofrNe.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/ImportExportModal-D4ckXCpj.js +1 -1
  37. agent_webui-2.8.1/agent/agent_webui/dist/assets/IntegrationsView-CesADaY9.js +2 -0
  38. agent_webui-2.7.1/agent/agent_webui/dist/assets/KnowledgeBaseView-DJzbVXf_.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/KnowledgeBaseView-CHEsj_tw.js +1 -1
  39. agent_webui-2.8.1/agent/agent_webui/dist/assets/KnowledgeView-B7qfWgXW.js +1 -0
  40. agent_webui-2.8.1/agent/agent_webui/dist/assets/LLMTemplatesView-QaMibiWE.js +1 -0
  41. agent_webui-2.7.1/agent/agent_webui/dist/assets/LearnView-CyFpsc5N.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/LearnView-BISyBztX.js +2 -2
  42. agent_webui-2.8.1/agent/agent_webui/dist/assets/LiveDashboardsView-CM8T3z-S.js +1 -0
  43. agent_webui-2.7.1/agent/agent_webui/dist/assets/MagmaView-DeUYSUus.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/MagmaView-BW8WOf8d.js +1 -1
  44. agent_webui-2.7.1/agent/agent_webui/dist/assets/MarketsCalendar-BJ4xSyWw.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/MarketsCalendar-EbKtpokY.js +1 -1
  45. agent_webui-2.7.1/agent/agent_webui/dist/assets/MarketsHome-CbspJWR4.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/MarketsHome-9vobkP13.js +1 -1
  46. agent_webui-2.7.1/agent/agent_webui/dist/assets/MarketsMenu-DHt2G1_0.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/MarketsMenu-CHxdEPCF.js +1 -1
  47. agent_webui-2.7.1/agent/agent_webui/dist/assets/MarketsNews-DZwg_as1.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/MarketsNews-C3RbvMk5.js +1 -1
  48. agent_webui-2.7.1/agent/agent_webui/dist/assets/MarketsPortfolio-DMM4Yl1Q.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/MarketsPortfolio-DyT66gGG.js +1 -1
  49. agent_webui-2.7.1/agent/agent_webui/dist/assets/MarketsShell-C1x1kWh-.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/MarketsShell-DKuBGMC2.js +1 -1
  50. agent_webui-2.7.1/agent/agent_webui/dist/assets/McpAppsView-l-sCScNo.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/McpAppsView-CKXmpZ9U.js +1 -1
  51. agent_webui-2.8.1/agent/agent_webui/dist/assets/MemoryView-BZEBvpR0.js +1 -0
  52. agent_webui-2.7.1/agent/agent_webui/dist/assets/NodeTypeBreakdown-Aede8Ovl.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/NodeTypeBreakdown-BBddvmF0.js +1 -1
  53. agent_webui-2.7.1/agent/agent_webui/dist/assets/NotFoundPage-y3NN-QVf.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/NotFoundPage-D-8pbBKi.js +1 -1
  54. agent_webui-2.7.1/agent/agent_webui/dist/assets/Notices-D17hdIJE.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/Notices-DNamjpvv.js +1 -1
  55. agent_webui-2.8.1/agent/agent_webui/dist/assets/ObjectExplorerView-DR-plmL6.js +1 -0
  56. agent_webui-2.7.1/agent/agent_webui/dist/assets/ObjectView-DG1Z_OYW.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/ObjectView-DX5PvjM9.js +1 -1
  57. agent_webui-2.8.1/agent/agent_webui/dist/assets/ObservabilityView-CtC3wFx4.js +1 -0
  58. agent_webui-2.8.1/agent/agent_webui/dist/assets/OperateWorkspace-DtojBKUU.js +1 -0
  59. agent_webui-2.8.1/agent/agent_webui/dist/assets/OpsPanelView-B00A1Ix-.js +1 -0
  60. agent_webui-2.8.1/agent/agent_webui/dist/assets/PrivacyPage-B5BNv8Wg.js +1 -0
  61. agent_webui-2.8.1/agent/agent_webui/dist/assets/PromptsView-D9879-Kf.js +1 -0
  62. agent_webui-2.8.1/agent/agent_webui/dist/assets/PublicPageLayout-CZjpqd4R.js +1 -0
  63. agent_webui-2.7.1/agent/agent_webui/dist/assets/SDDView-B0meX0p3.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/SDDView-Ws5WYUZb.js +1 -1
  64. agent_webui-2.7.1/agent/agent_webui/dist/assets/SchedulingView-DvwK95G0.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/SchedulingView-BBgfCFgt.js +1 -1
  65. agent_webui-2.7.1/agent/agent_webui/dist/assets/SchemaView-o5YEfujF.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/SchemaView-DGhMmwmC.js +1 -1
  66. agent_webui-2.8.1/agent/agent_webui/dist/assets/SessionsView-jRaF2PEh.js +1 -0
  67. agent_webui-2.7.1/agent/agent_webui/dist/assets/SharePage-5sxMYGoz.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/SharePage-C4CYYKR7.js +1 -1
  68. agent_webui-2.8.1/agent/agent_webui/dist/assets/SkillsView-BkkkGLS1.js +1 -0
  69. agent_webui-2.8.1/agent/agent_webui/dist/assets/SparqlView-CRSmtx87.js +1 -0
  70. agent_webui-2.8.1/agent/agent_webui/dist/assets/SystemStatusView-CBa2hfoD.js +1 -0
  71. agent_webui-2.8.1/agent/agent_webui/dist/assets/TableExplorerView-DgiC5cSe.js +1 -0
  72. agent_webui-2.8.1/agent/agent_webui/dist/assets/TemporalGraphView-DVaIqhF7.js +1 -0
  73. agent_webui-2.8.1/agent/agent_webui/dist/assets/TermsPage-CwXcVECt.js +1 -0
  74. agent_webui-2.7.1/agent/agent_webui/dist/assets/ThankYouPage-BvFj5K9A.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/ThankYouPage-CkeGuK6U.js +1 -1
  75. agent_webui-2.8.1/agent/agent_webui/dist/assets/TrendBadge-Cto5r-1S.js +1 -0
  76. agent_webui-2.8.1/agent/agent_webui/dist/assets/UsageView-Bhyk0gOG.js +1 -0
  77. agent_webui-2.8.1/agent/agent_webui/dist/assets/UserManagementView-xO_SUluQ.js +1 -0
  78. agent_webui-2.7.1/agent/agent_webui/dist/assets/VertexView-E0vs0cRH.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/VertexView-Bkljwv0n.js +1 -1
  79. agent_webui-2.8.1/agent/agent_webui/dist/assets/VizDemoView-B58FwOSu.js +1 -0
  80. agent_webui-2.8.1/agent/agent_webui/dist/assets/WorkWorkspace-B4PMyWKO.js +1 -0
  81. agent_webui-2.8.1/agent/agent_webui/dist/assets/WorkflowEditorView-HfJAp1p3.js +7 -0
  82. agent_webui-2.8.1/agent/agent_webui/dist/assets/WorkspaceIDEView-CR_Hg9Rc.js +1 -0
  83. agent_webui-2.8.1/agent/agent_webui/dist/assets/arrow-up-DpBEFU1W.js +1 -0
  84. agent_webui-2.8.1/agent/agent_webui/dist/assets/circle-dot-In4UilqT.js +1 -0
  85. agent_webui-2.8.1/agent/agent_webui/dist/assets/identity-CwkFopGE.js +1 -0
  86. agent_webui-2.7.1/agent/agent_webui/dist/assets/index-B3Hz4lzB.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/index-BL_57l7k.js +17 -17
  87. agent_webui-2.8.1/agent/agent_webui/dist/assets/index-BMoFkgmK.css +2 -0
  88. agent_webui-2.8.1/agent/agent_webui/dist/assets/loaded-workspace-commands-DS7_oKFh.js +1 -0
  89. agent_webui-2.7.1/agent/agent_webui/dist/assets/model-C4AzLQrj.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/model-BOQvdzSX.js +1 -1
  90. agent_webui-2.8.1/agent/agent_webui/dist/assets/queries-H1CRh4k4.js +1 -0
  91. agent_webui-2.7.1/agent/agent_webui/dist/assets/status-message-ovrDYMYX.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/status-message-JWIBft3W.js +1 -1
  92. agent_webui-2.8.1/agent/agent_webui/dist/assets/tabs-A3rvoq-T.js +1 -0
  93. agent_webui-2.8.1/agent/agent_webui/dist/assets/undo-2-D4EYZLW8.js +1 -0
  94. agent_webui-2.8.1/agent/agent_webui/dist/assets/uql-H85wtqTc.js +1 -0
  95. agent_webui-2.7.1/agent/agent_webui/dist/assets/useMutation-Bjdc9UtI.js → agent_webui-2.8.1/agent/agent_webui/dist/assets/useMutation-jh7EKgU0.js +1 -1
  96. agent_webui-2.8.1/agent/agent_webui/dist/assets/useQuery-BCV_z3lS.js +1 -0
  97. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/index.html +3 -3
  98. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/spa-routes.json +4 -0
  99. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/oidc_session.py +1 -1
  100. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/orchestrator_model.py +93 -29
  101. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/server.py +102 -20
  102. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui.egg-info/PKG-INFO +9 -4
  103. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui.egg-info/SOURCES.txt +90 -78
  104. {agent_webui-2.7.1 → agent_webui-2.8.1}/pyproject.toml +5 -5
  105. agent_webui-2.8.1/tests/test_explicit_auth_modes.py +188 -0
  106. {agent_webui-2.7.1 → agent_webui-2.8.1}/tests/test_release_publication.py +1 -1
  107. agent_webui-2.7.1/agent/agent_webui/dist/assets/AdminView-BdhlXNuH.js +0 -1
  108. agent_webui-2.7.1/agent/agent_webui/dist/assets/ArboraReadinessView-BkGEkah-.js +0 -1
  109. agent_webui-2.7.1/agent/agent_webui/dist/assets/AtlasView-De6w_9WH.js +0 -5
  110. agent_webui-2.7.1/agent/agent_webui/dist/assets/BrokerView-DHE8-a7g.js +0 -1
  111. agent_webui-2.7.1/agent/agent_webui/dist/assets/ChartPage-CajmeMxT.js +0 -1
  112. agent_webui-2.7.1/agent/agent_webui/dist/assets/CypherReplView-BFVNSbHf.js +0 -1
  113. agent_webui-2.7.1/agent/agent_webui/dist/assets/DashboardView-JHHk8nfw.js +0 -1
  114. agent_webui-2.7.1/agent/agent_webui/dist/assets/EcosystemView-BxdVgmYl.js +0 -1
  115. agent_webui-2.7.1/agent/agent_webui/dist/assets/FilesView-B4kygc4_.js +0 -1
  116. agent_webui-2.7.1/agent/agent_webui/dist/assets/Graph3DLodView-CNt0ZZ1f.js +0 -1
  117. agent_webui-2.7.1/agent/agent_webui/dist/assets/GraphCanvas-CvF9sWHU.js +0 -1
  118. agent_webui-2.7.1/agent/agent_webui/dist/assets/GraphView-DtSYTFIU.js +0 -1
  119. agent_webui-2.7.1/agent/agent_webui/dist/assets/IntegrationsView-DanxQx4E.js +0 -2
  120. agent_webui-2.7.1/agent/agent_webui/dist/assets/KnowledgeView-0lzdQNlj.js +0 -1
  121. agent_webui-2.7.1/agent/agent_webui/dist/assets/LLMTemplatesView-DpYhR3Rz.js +0 -1
  122. agent_webui-2.7.1/agent/agent_webui/dist/assets/LiveDashboardsView-ESAfLAEw.js +0 -1
  123. agent_webui-2.7.1/agent/agent_webui/dist/assets/MemoryView-Dghm1rMT.js +0 -1
  124. agent_webui-2.7.1/agent/agent_webui/dist/assets/ObjectExplorerView-DdPfSjOg.js +0 -1
  125. agent_webui-2.7.1/agent/agent_webui/dist/assets/ObservabilityView-Ce5o66gv.js +0 -1
  126. agent_webui-2.7.1/agent/agent_webui/dist/assets/OpsPanelView-CDke42HU.js +0 -1
  127. agent_webui-2.7.1/agent/agent_webui/dist/assets/PrivacyPage-DypYppFK.js +0 -1
  128. agent_webui-2.7.1/agent/agent_webui/dist/assets/PromptsView-C0soAhv5.js +0 -1
  129. agent_webui-2.7.1/agent/agent_webui/dist/assets/PublicPageLayout-1ji-4LZL.js +0 -1
  130. agent_webui-2.7.1/agent/agent_webui/dist/assets/SessionsView-DSoZk_Lz.js +0 -1
  131. agent_webui-2.7.1/agent/agent_webui/dist/assets/SkillsView-CL-inq1F.js +0 -1
  132. agent_webui-2.7.1/agent/agent_webui/dist/assets/SparqlView-Duik6wYZ.js +0 -1
  133. agent_webui-2.7.1/agent/agent_webui/dist/assets/SystemStatusView-D7PxxotJ.js +0 -1
  134. agent_webui-2.7.1/agent/agent_webui/dist/assets/TableExplorerView-Jt0S_NKW.js +0 -1
  135. agent_webui-2.7.1/agent/agent_webui/dist/assets/TemporalGraphView-DF-se9oo.js +0 -1
  136. agent_webui-2.7.1/agent/agent_webui/dist/assets/TermsPage-CDnQDbgV.js +0 -1
  137. agent_webui-2.7.1/agent/agent_webui/dist/assets/TrendBadge-DFvlzJv5.js +0 -1
  138. agent_webui-2.7.1/agent/agent_webui/dist/assets/UsageView-exhd6ewz.js +0 -1
  139. agent_webui-2.7.1/agent/agent_webui/dist/assets/UserManagementView-DFsbzkZb.js +0 -1
  140. agent_webui-2.7.1/agent/agent_webui/dist/assets/VizDemoView-Bt3r5KAC.js +0 -1
  141. agent_webui-2.7.1/agent/agent_webui/dist/assets/WorkflowEditorView-6bMv23QZ.js +0 -7
  142. agent_webui-2.7.1/agent/agent_webui/dist/assets/WorkspaceIDEView-BXzXC4zp.js +0 -1
  143. agent_webui-2.7.1/agent/agent_webui/dist/assets/identity-C3qnrvHo.js +0 -1
  144. agent_webui-2.7.1/agent/agent_webui/dist/assets/index-BRlMMQsQ.css +0 -2
  145. agent_webui-2.7.1/agent/agent_webui/dist/assets/queries-PjkfUoGJ.js +0 -1
  146. agent_webui-2.7.1/agent/agent_webui/dist/assets/tabs-BxSTPadT.js +0 -1
  147. agent_webui-2.7.1/agent/agent_webui/dist/assets/useQuery-BGefm_dX.js +0 -1
  148. {agent_webui-2.7.1 → agent_webui-2.8.1}/LICENSE +0 -0
  149. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__init__.py +0 -0
  150. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/conftest.py +0 -0
  151. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_api_extensions.py +0 -0
  152. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_bound_sweep_regressions.py +0 -0
  153. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_browser_control.py +0 -0
  154. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_bug_012_github_gitlab_contract.py +0 -0
  155. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_chat_resource_routes.py +0 -0
  156. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_contact_delivery.py +0 -0
  157. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_files_endpoints.py +0 -0
  158. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_host.py +0 -0
  159. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_markets_app.py +0 -0
  160. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_observability.py +0 -0
  161. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_oidc_session.py +0 -0
  162. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_parity_contract.py +0 -0
  163. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_pydantic_ai_compat.py +0 -0
  164. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_rbac.py +0 -0
  165. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_spa_http_status.py +0 -0
  166. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/__tests__/test_workspace_helpers_chokepoint.py +0 -0
  167. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/apps/__init__.py +0 -0
  168. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/apps/markets/__init__.py +0 -0
  169. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/apps/markets/catalog.py +0 -0
  170. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/apps/markets/chart.py +0 -0
  171. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/apps/markets/gateway.py +0 -0
  172. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/apps/markets/scanner.py +0 -0
  173. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/apps/markets/series.py +0 -0
  174. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/apps/markets/session.py +0 -0
  175. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/apps/markets/snapshots.py +0 -0
  176. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/apps/markets/timeframes.py +0 -0
  177. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/browser_control.py +0 -0
  178. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/browser_control_canonical.py +0 -0
  179. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/apple-touch-icon.png +0 -0
  180. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/ChartPanel-Cxpkw3a6.js +0 -0
  181. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/InterVariable-DiVDrmQJ.woff2 +0 -0
  182. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/LegalPageContent-BmhwYoKV.js +0 -0
  183. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/SessionExpiredNotice-CMttDxWl.js +0 -0
  184. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/WorkflowEditorView-DLioOiRN.css +0 -0
  185. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/activity-DupAOJCR.js +0 -0
  186. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/api-jtHn_WxH.js +0 -0
  187. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/api-validation-CCoR_LRu.js +0 -0
  188. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/app-window-KMAPJoaW.js +0 -0
  189. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/badge-nQZ87mVE.js +0 -0
  190. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/braces-BNz2iAeD.js +0 -0
  191. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/bundle-mjs-DIyOrgL5.js +0 -0
  192. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/check-CPVKKX8l.js +0 -0
  193. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/chevron-down-DYWnPQti.js +0 -0
  194. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/chevron-left-BaGXvfgm.js +0 -0
  195. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/chevron-right-gs8WU8XT.js +0 -0
  196. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/chevron-up-C-rjGU5C.js +0 -0
  197. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/chunk-D32TOXHM-KueescCg.js +0 -0
  198. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/circle-alert-ByZ-1ERr.js +0 -0
  199. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/contact-C94LhKRg.js +0 -0
  200. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/createLucideIcon-DTQSidPf.js +0 -0
  201. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/dist-2txhAIHO.js +0 -0
  202. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/dist-BHmo3Yb6.js +0 -0
  203. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/dist-BKkt828_.js +0 -0
  204. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/dist-BLRfKgTy.js +0 -0
  205. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/dist-BjAObXUn.js +0 -0
  206. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/dist-Bq6o2UDR.js +0 -0
  207. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/dist-CWmwEm73.js +0 -0
  208. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/dist-DMVqwVuR.js +0 -0
  209. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/dist-DcreYulP.js +0 -0
  210. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/dist-mp1aFJDC.js +0 -0
  211. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/es2015-CgZynitj.js +0 -0
  212. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/external-link-Dyd5OsGm.js +0 -0
  213. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/eye-D0gCj30e.js +0 -0
  214. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/file-text-DqorJKDA.js +0 -0
  215. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/folder-open-BrzeUmMg.js +0 -0
  216. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/format-DHsGNrOH.js +0 -0
  217. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/funnel-Y4IuN8Q7.js +0 -0
  218. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/graphology-layout-forceatlas2-CF_uOjtN.js +0 -0
  219. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/hard-drive-9fR5RFS9.js +0 -0
  220. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/highlighted-body-KQOG7T2V-qSdnQsR5.js +0 -0
  221. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/hourglass-1ui486hR.js +0 -0
  222. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/layout-grid-B4IFpzLD.js +0 -0
  223. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/layout.worker-CnC9u5pP.js +0 -0
  224. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/link-2-a9RZxW2S.js +0 -0
  225. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/mermaid-MCJ5UELQ-F6vEfdbO.js +0 -0
  226. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/play-D3mjq--Q.js +0 -0
  227. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/plus-s20KYBeu.js +0 -0
  228. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/preload-helper-CRzLMJPS.js +0 -0
  229. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/react-dom-DAxA-E-a.js +0 -0
  230. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/refresh-cw-BVhl5aJX.js +0 -0
  231. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/save-CuEdPPgC.js +0 -0
  232. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/scan-search-GrqJngl3.js +0 -0
  233. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/scroll-area-srEWz9Q3.js +0 -0
  234. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/server-CE-xbAAj.js +0 -0
  235. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/sliders-vertical-Cr4E50uY.js +0 -0
  236. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/sparkles-Bae0tRI0.js +0 -0
  237. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/switch-B9Yml2pU.js +0 -0
  238. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/tag-D1RiwxuF.js +0 -0
  239. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/theme-colors-DKGWsgC0.js +0 -0
  240. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/transport-Din6U5N9.js +0 -0
  241. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/unavailable-notice-B7WdWNor.js +0 -0
  242. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/upload-DcybBZCN.js +0 -0
  243. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/utils-C0okervd.js +0 -0
  244. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/wifi-off-Dz91unNp.js +0 -0
  245. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/assets/x-BdA_yxUR.js +0 -0
  246. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/favicon-16x16.png +0 -0
  247. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/favicon-32x32.png +0 -0
  248. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/favicon-48x48.png +0 -0
  249. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/favicon.ico +0 -0
  250. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/favicon.png +0 -0
  251. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/favicon.svg +0 -0
  252. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/icon-192x192.png +0 -0
  253. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/icon-512x512.png +0 -0
  254. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/og-image-v1.png +0 -0
  255. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/og-image-v1.svg +0 -0
  256. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/robots.txt +0 -0
  257. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/site.webmanifest +0 -0
  258. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/dist/sitemap.xml +0 -0
  259. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/host.py +0 -0
  260. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/icon.png +0 -0
  261. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/observability.py +0 -0
  262. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/public_shell.py +0 -0
  263. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/rbac.py +0 -0
  264. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/skills/__init__.py +0 -0
  265. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/skills/agent-webui-development/SKILL.md +0 -0
  266. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/skills/kg-webui-admin/SKILL.md +0 -0
  267. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/skills/kg-webui-dashboards/SKILL.md +0 -0
  268. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/skills/kg-webui-extraction/SKILL.md +0 -0
  269. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/skills/kg-webui-graphviz/SKILL.md +0 -0
  270. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/skills/kg-webui-ontology-operator/SKILL.md +0 -0
  271. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui/skills/kg-webui-swe/SKILL.md +0 -0
  272. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui.egg-info/dependency_links.txt +0 -0
  273. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui.egg-info/entry_points.txt +0 -0
  274. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui.egg-info/requires.txt +0 -0
  275. {agent_webui-2.7.1 → agent_webui-2.8.1}/agent/agent_webui.egg-info/top_level.txt +0 -0
  276. {agent_webui-2.7.1 → agent_webui-2.8.1}/setup.cfg +0 -0
  277. {agent_webui-2.7.1 → agent_webui-2.8.1}/tests/test_dashboard_entrypoint.py +0 -0
  278. {agent_webui-2.7.1 → agent_webui-2.8.1}/tests/test_eslint_hook_contract.py +0 -0
  279. {agent_webui-2.7.1 → agent_webui-2.8.1}/tests/test_gate_wrappers.py +0 -0
  280. {agent_webui-2.7.1 → agent_webui-2.8.1}/tests/test_graph_visualization.py +0 -0
  281. {agent_webui-2.7.1 → agent_webui-2.8.1}/tests/test_health_liveness_endpoint.py +0 -0
  282. {agent_webui-2.7.1 → agent_webui-2.8.1}/tests/test_identity_boundary.py +0 -0
  283. {agent_webui-2.7.1 → agent_webui-2.8.1}/tests/test_init.py +0 -0
  284. {agent_webui-2.7.1 → agent_webui-2.8.1}/tests/test_log_failure_error_code.py +0 -0
  285. {agent_webui-2.7.1 → agent_webui-2.8.1}/tests/test_package_author_privacy.py +0 -0
  286. {agent_webui-2.7.1 → agent_webui-2.8.1}/tests/test_privacy_boundaries.py +0 -0
  287. {agent_webui-2.7.1 → agent_webui-2.8.1}/tests/test_release_concurrency.py +0 -0
  288. {agent_webui-2.7.1 → agent_webui-2.8.1}/tests/test_release_gate_order.py +0 -0
  289. {agent_webui-2.7.1 → agent_webui-2.8.1}/tests/test_startup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-webui
3
- Version: 2.7.1
3
+ Version: 2.8.1
4
4
  Summary: Agent Web Interface for Pydantic AI Agents
5
5
  Author-email: Repository Maintainers <maintainers@knuckles.team>
6
6
  License: MIT
@@ -9,7 +9,10 @@ Classifier: License :: OSI Approved :: MIT License
9
9
  Classifier: Environment :: Console
10
10
  Classifier: Operating System :: POSIX :: Linux
11
11
  Classifier: Programming Language :: Python :: 3
12
- Requires-Python: <3.15,>=3.12
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Requires-Python: >=3.12
13
16
  Description-Content-Type: text/markdown
14
17
  License-File: LICENSE
15
18
  Requires-Dist: agent-utilities<4.0.0,>=3.0.0
@@ -97,7 +100,7 @@ credentials and gateway delegation on the server side.
97
100
  |---|---|
98
101
  | Browser presentation, local interaction state, accessible route composition, and the FastAPI boundary | Arbora owns public routing, identity, policy, and fleet supervision; Agent Utilities owns agent behavior; Epistemic Graph owns durable knowledge; connector services own external-system effects |
99
102
 
100
- Current package Version: 2.7.1.
103
+ Current package Version: 2.8.1.
101
104
 
102
105
  ## Key capabilities
103
106
 
@@ -126,7 +129,9 @@ then use the shared platform map to move between components:
126
129
 
127
130
  ## Architecture
128
131
 
129
- ![Runtime architecture: people use Agent Web UI, Agent Terminal UI, Geniusbot, and Arbora-hosted messaging. MCP, REST, and A2A clients enter through Arbora; source systems flow through Agent Connector SDK into Epistemic Graph.](https://raw.githubusercontent.com/Knuckles-Team/epistemic-graph/main/docs/assets/runtime-architecture.svg)
132
+ [![Runtime architecture: people use Agent Web UI, Agent Terminal UI, Geniusbot, and Arbora-hosted messaging. MCP, REST, and A2A clients enter through Arbora; source systems flow through Agent Connector SDK into Epistemic Graph.](https://raw.githubusercontent.com/Knuckles-Team/epistemic-graph/main/docs/assets/runtime-architecture.svg)](https://knuckles-team.github.io/.github/architecture/#webui)
133
+
134
+ [Explore the live architecture](https://knuckles-team.github.io/.github/architecture/#webui)
130
135
 
131
136
  People also enter through Agent Terminal UI and Geniusbot or Arbora-hosted
132
137
  messaging; Agent Terminal UI exposes REST operations, with no ACP conversational
@@ -54,7 +54,7 @@ credentials and gateway delegation on the server side.
54
54
  |---|---|
55
55
  | Browser presentation, local interaction state, accessible route composition, and the FastAPI boundary | Arbora owns public routing, identity, policy, and fleet supervision; Agent Utilities owns agent behavior; Epistemic Graph owns durable knowledge; connector services own external-system effects |
56
56
 
57
- Current package Version: 2.7.1.
57
+ Current package Version: 2.8.1.
58
58
 
59
59
  ## Key capabilities
60
60
 
@@ -83,7 +83,9 @@ then use the shared platform map to move between components:
83
83
 
84
84
  ## Architecture
85
85
 
86
- ![Runtime architecture: people use Agent Web UI, Agent Terminal UI, Geniusbot, and Arbora-hosted messaging. MCP, REST, and A2A clients enter through Arbora; source systems flow through Agent Connector SDK into Epistemic Graph.](https://raw.githubusercontent.com/Knuckles-Team/epistemic-graph/main/docs/assets/runtime-architecture.svg)
86
+ [![Runtime architecture: people use Agent Web UI, Agent Terminal UI, Geniusbot, and Arbora-hosted messaging. MCP, REST, and A2A clients enter through Arbora; source systems flow through Agent Connector SDK into Epistemic Graph.](https://raw.githubusercontent.com/Knuckles-Team/epistemic-graph/main/docs/assets/runtime-architecture.svg)](https://knuckles-team.github.io/.github/architecture/#webui)
87
+
88
+ [Explore the live architecture](https://knuckles-team.github.io/.github/architecture/#webui)
87
89
 
88
90
  People also enter through Agent Terminal UI and Geniusbot or Arbora-hosted
89
91
  messaging; Agent Terminal UI exposes REST operations, with no ACP conversational
@@ -0,0 +1,218 @@
1
+ """WEBUI-API-R011.2: conversation labels and admitted run identity stay distinct."""
2
+
3
+ # spec: WEBUI-API-R011.2.1
4
+
5
+ import asyncio
6
+
7
+ import pytest
8
+ from agent_webui.orchestrator_model import (
9
+ _conversation_session_id,
10
+ _run_identity,
11
+ build_orchestrator_model,
12
+ )
13
+ from pydantic_ai import Agent
14
+ from pydantic_ai.messages import ModelRequest, UserPromptPart
15
+
16
+
17
+ def request(text='hello', conversation_id=None):
18
+ return ModelRequest(
19
+ parts=[UserPromptPart(content=text)], conversation_id=conversation_id
20
+ )
21
+
22
+
23
+ def task_result(task_id, context='owned-context'):
24
+ return {
25
+ 'value': {
26
+ 'id': task_id,
27
+ 'contextId': context,
28
+ 'metadata': {
29
+ 'arbora': {
30
+ 'runId': 'run-' + task_id,
31
+ 'runTraceRef': 'opaque-ref-' + task_id,
32
+ }
33
+ },
34
+ 'artifacts': [{'parts': [{'kind': 'text', 'text': 'reply-' + task_id}]}],
35
+ }
36
+ }
37
+
38
+
39
+ def test_explicit_identity_is_stable_not_content_derived():
40
+ assert _conversation_session_id([request('one', 'c1')]) == 'webui:c1'
41
+ assert _conversation_session_id([request('two', 'c1')]) == 'webui:c1'
42
+ assert _conversation_session_id([request('one', 'c2')]) == 'webui:c2'
43
+ assert _conversation_session_id([request()]) != _conversation_session_id(
44
+ [request()]
45
+ )
46
+
47
+
48
+ def test_conflicting_identity_refused():
49
+ with pytest.raises(ValueError, match='Conflicting'):
50
+ _conversation_session_id(
51
+ [request(conversation_id='a'), request(conversation_id='b')]
52
+ )
53
+
54
+
55
+ def test_explicit_references_only_no_guessed_trace():
56
+ metadata = _run_identity(task_result('t1'), 'webui:c1')
57
+ assert metadata is not None
58
+ identity = metadata['arbora_run']
59
+ assert identity == {
60
+ 'conversation_context': 'webui:c1',
61
+ 'task_id': 't1',
62
+ 'context_id': 'owned-context',
63
+ 'run_id': 'run-t1',
64
+ 'run_trace_ref': 'opaque-ref-t1',
65
+ }
66
+ assert _run_identity({'value': {'status': {}}}, 'webui:c1') is None
67
+ assert _run_identity({'result': task_result('nested')}, 'webui:c1') is None
68
+ assert _run_identity({'value': {'id': 't', 'contextId': 'c'}}, 'webui:c1') == {
69
+ 'arbora_run': {
70
+ 'conversation_context': 'webui:c1',
71
+ 'task_id': 't',
72
+ 'context_id': 'c',
73
+ }
74
+ }
75
+
76
+
77
+ @pytest.mark.parametrize(
78
+ 'field,value', [('id', 1), ('contextId', ''), ('contextId', ['c'])]
79
+ )
80
+ def test_invalid_returned_identity_refused(field, value):
81
+ result = task_result('t1')
82
+ result['value'][field] = value
83
+ assert _run_identity(result, 'webui:c1') is None
84
+
85
+
86
+ async def test_stream_metadata_is_request_local_and_preserves_exact_refs():
87
+ calls = []
88
+
89
+ async def invoke(op, params, *, idempotency_key):
90
+ context = params['message']['contextId']
91
+ calls.append((context, idempotency_key))
92
+ await asyncio.sleep(0)
93
+ return task_result(context)
94
+
95
+ agent = Agent(build_orchestrator_model(invoke=invoke))
96
+
97
+ async def run(conversation):
98
+ async with agent.run_stream('hello', conversation_id=conversation) as result:
99
+ await result.get_output()
100
+ return result.response
101
+
102
+ one, two = await asyncio.gather(run('one'), run('two'))
103
+ assert one.metadata['arbora_run']['task_id'] == 'webui:one'
104
+ assert two.metadata['arbora_run']['task_id'] == 'webui:two'
105
+ assert one.metadata['arbora_run']['run_trace_ref'] == 'opaque-ref-webui:one'
106
+ from pydantic_ai.ui.vercel_ai import VercelAIAdapter
107
+
108
+ wire = VercelAIAdapter.dump_messages([one])[0]
109
+ assert wire.metadata['arbora_run'] == one.metadata['arbora_run']
110
+ # Repeated turns share conversation identity, not a fabricated task/run ID.
111
+ again = await run('one')
112
+ assert again.metadata['arbora_run']['conversation_context'] == 'webui:one'
113
+ assert calls[0][1] != calls[-1][1]
114
+ assert calls[-1][0] == 'webui:one'
115
+
116
+
117
+ async def test_failed_stream_does_not_reuse_previous_identity():
118
+ calls = 0
119
+
120
+ async def invoke(op, params, *, idempotency_key):
121
+ nonlocal calls
122
+ calls += 1
123
+ if calls == 2:
124
+ raise RuntimeError('unavailable')
125
+ return task_result('first' if calls == 1 else 'third')
126
+
127
+ agent = Agent(build_orchestrator_model(invoke=invoke))
128
+ first = await agent.run('first', conversation_id='one')
129
+ assert first.response.metadata['arbora_run']['task_id'] == 'first'
130
+ with pytest.raises(RuntimeError, match='unavailable'):
131
+ async with agent.run_stream('second', conversation_id='two') as result:
132
+ await result.get_output()
133
+ async with agent.run_stream('retry', conversation_id='two') as result:
134
+ await result.get_output()
135
+ assert result.response.metadata['arbora_run']['task_id'] == 'third'
136
+ assert (
137
+ result.response.metadata['arbora_run']['conversation_context']
138
+ == 'webui:two'
139
+ )
140
+
141
+
142
+ @pytest.mark.parametrize('malformed', [False, True])
143
+ async def test_real_vercel_stream_propagates_served_identity_without_repeating_effects(
144
+ malformed,
145
+ ):
146
+ import json
147
+
148
+ from pydantic_ai.ui.vercel_ai import VercelAIAdapter
149
+ from starlette.requests import Request
150
+
151
+ calls = []
152
+
153
+ async def invoke(op, params, *, idempotency_key):
154
+ calls.append(params)
155
+ result = task_result('wire-task')
156
+ if malformed:
157
+ result['value']['id'] = 42
158
+ return {'ok': True, 'result': result, 'meta': {'registry_digest': 'test'}}
159
+
160
+ payload = json.dumps(
161
+ {
162
+ 'id': '/selected',
163
+ 'trigger': 'submit-message',
164
+ 'messages': [
165
+ {
166
+ 'id': 'u1',
167
+ 'role': 'user',
168
+ 'parts': [{'type': 'text', 'text': 'hello'}],
169
+ }
170
+ ],
171
+ }
172
+ ).encode()
173
+
174
+ async def receive():
175
+ return {'type': 'http.request', 'body': payload, 'more_body': False}
176
+
177
+ request = Request(
178
+ {
179
+ 'type': 'http',
180
+ 'method': 'POST',
181
+ 'path': '/api/chats/messages',
182
+ 'headers': [(b'content-type', b'application/json')],
183
+ },
184
+ receive,
185
+ )
186
+ response = await VercelAIAdapter.dispatch_request(
187
+ request, agent=Agent(build_orchestrator_model(invoke=invoke)), sdk_version=7
188
+ )
189
+ assert hasattr(response, 'body_iterator'), response.body
190
+ chunks = [chunk async for chunk in response.body_iterator]
191
+ body = ''.join(
192
+ chunk.decode() if isinstance(chunk, bytes) else chunk for chunk in chunks
193
+ )
194
+ assert len(calls) == 1
195
+ assert calls[0]['message']['contextId'] == 'webui:/selected'
196
+ assert 'reply-wire-task' in body
197
+ events = [
198
+ json.loads(line[6:])
199
+ for line in body.splitlines()
200
+ if line.startswith('data: ') and line != 'data: [DONE]'
201
+ ]
202
+ metadata = [
203
+ event['messageMetadata']
204
+ for event in events
205
+ if event['type'] == 'message-metadata'
206
+ ]
207
+ assert len(metadata) == 1
208
+ if malformed:
209
+ assert 'arbora_run' not in metadata[0]
210
+ else:
211
+ assert metadata[0]['arbora_run']['task_id'] == 'wire-task'
212
+ assert metadata[0]['arbora_run']['run_trace_ref'] == 'opaque-ref-wire-task'
213
+
214
+
215
+ def test_error_envelope_cannot_supply_identity():
216
+ assert (
217
+ _run_identity({'ok': False, 'result': task_result('fake')}, 'webui:c') is None
218
+ )
@@ -270,7 +270,7 @@ def _run_html_document(body_chunks: list[bytes], policy: str | None = None) -> l
270
270
  return messages
271
271
 
272
272
 
273
- @pytest.mark.spec('DS-08')
273
+ @pytest.mark.spec('WEBUI-DESIGN-R009')
274
274
  def test_html_documents_carry_a_fresh_style_nonce() -> None:
275
275
  chunks = [b'<meta property="csp-nonce" nonce="AGENT_WEBUI_', b'CSP_NONCE">']
276
276
  first = _run_html_document(chunks)
@@ -185,7 +185,7 @@ def _client(app: Any, scope: str = _ADMIN) -> TestClient:
185
185
  ),
186
186
  ],
187
187
  )
188
- # spec: APIUI-06.1
188
+ # spec: WEBUI-API-R011.1
189
189
  def test_read_routes_project_the_served_operation(
190
190
  app, arbora, method, path, body, op_id, value, sent, expected
191
191
  ) -> None:
@@ -272,7 +272,7 @@ def test_a_arbora_refusal_keeps_its_status(app, arbora, code, status) -> None:
272
272
  ('/cron/calendar', 'schedule.tasks.read'),
273
273
  ],
274
274
  )
275
- # spec: APIUI-06.1
275
+ # spec: WEBUI-API-R011.1
276
276
  def test_routes_without_a_served_operation_answer_not_available(
277
277
  app, arbora, path, operation
278
278
  ) -> None:
@@ -18,7 +18,7 @@ import uuid
18
18
  from collections.abc import Awaitable, Callable
19
19
  from concurrent import futures as _futures
20
20
  from dataclasses import dataclass, replace
21
- from datetime import datetime, timezone
21
+ from datetime import UTC, datetime
22
22
  from ipaddress import ip_address
23
23
  from pathlib import Path
24
24
  from typing import Annotated, Any, Literal
@@ -1320,9 +1320,7 @@ def _list_files_dir_entry(dir_path: Path, base_path: Path) -> dict[str, Any] | N
1320
1320
  return {
1321
1321
  'name': str(dir_path.relative_to(base_path)),
1322
1322
  'size': 0,
1323
- 'modified_iso': datetime.fromtimestamp(
1324
- st.st_mtime, tz=timezone.utc
1325
- ).isoformat(),
1323
+ 'modified_iso': datetime.fromtimestamp(st.st_mtime, tz=UTC).isoformat(),
1326
1324
  'is_dir': True,
1327
1325
  }
1328
1326
 
@@ -1339,9 +1337,7 @@ def _list_files_file_entry(
1339
1337
  return {
1340
1338
  'name': str(file_path.relative_to(base_path)),
1341
1339
  'size': st.st_size,
1342
- 'modified_iso': datetime.fromtimestamp(
1343
- st.st_mtime, tz=timezone.utc
1344
- ).isoformat(),
1340
+ 'modified_iso': datetime.fromtimestamp(st.st_mtime, tz=UTC).isoformat(),
1345
1341
  'is_dir': False,
1346
1342
  }
1347
1343
 
@@ -5586,7 +5582,7 @@ def _system_prompt_record(sys_prompt: str) -> dict[str, Any]:
5586
5582
  'description': 'The default system prompt configured for this agent.',
5587
5583
  'author': 'System',
5588
5584
  'version': 1,
5589
- 'created_at': datetime.now(timezone.utc).isoformat(),
5585
+ 'created_at': datetime.now(UTC).isoformat(),
5590
5586
  }
5591
5587
 
5592
5588
 
@@ -9921,7 +9917,7 @@ def _atlas_response_body(response: JSONResponse) -> Any | None:
9921
9917
 
9922
9918
 
9923
9919
  def _atlas_observed_at() -> str:
9924
- return datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z')
9920
+ return datetime.now(UTC).isoformat().replace('+00:00', 'Z')
9925
9921
 
9926
9922
 
9927
9923
  def _atlas_valid_reference(value: Any) -> str | None:
@@ -11,7 +11,7 @@ from __future__ import annotations
11
11
  import re
12
12
  import time
13
13
  from collections.abc import Awaitable, Callable
14
- from typing import Annotated, Any, Literal, TypeVar
14
+ from typing import Annotated, Any, Literal
15
15
 
16
16
  from fastapi import APIRouter, HTTPException, Query
17
17
  from pydantic import AfterValidator, BaseModel, ConfigDict, Field
@@ -39,7 +39,6 @@ from .snapshots import (
39
39
  )
40
40
  from .timeframes import TIMEFRAMES, range_start
41
41
 
42
- T = TypeVar('T')
43
42
  Timeframe = Literal['1m', '15m', '1h', '4h', '12h', '1D', '1W', '1M']
44
43
  RangeCode = Literal['1M', '3M', '1Y', '5Y', 'all']
45
44
  AssetClass = Literal[
@@ -111,7 +110,7 @@ def _layers(raw: str) -> frozenset[str]:
111
110
  return chosen
112
111
 
113
112
 
114
- async def _guarded(call: Awaitable[T]) -> T:
113
+ async def _guarded[T](call: Awaitable[T]) -> T:
115
114
  try:
116
115
  return await call
117
116
  except MarketsRefused as error:
@@ -0,0 +1,99 @@
1
+ """Immutable deployment identity selection, never a request-controlled fallback."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from enum import StrEnum
7
+
8
+
9
+ class AuthMode(StrEnum):
10
+ """The operator's explicit identity owner; legacy defaults stay protected."""
11
+
12
+ REQUIRED = 'required'
13
+ NONE = 'none'
14
+ EG = 'eg'
15
+ OIDC = 'oidc'
16
+
17
+
18
+ def resolve_auth_mode(value: str | None) -> AuthMode:
19
+ """Reject unknown settings rather than accidentally enabling anonymous access."""
20
+ try:
21
+ return AuthMode('required' if value is None else value)
22
+ except ValueError:
23
+ raise ValueError(
24
+ 'WebUI auth mode must be required, none, eg, or oidc'
25
+ ) from None
26
+
27
+
28
+ def validate_auth_mode(
29
+ mode: AuthMode,
30
+ *,
31
+ loopback: bool,
32
+ has_verifier: bool,
33
+ has_boundary: bool,
34
+ has_browser_sso: bool,
35
+ boundary_mode: str | None = None,
36
+ ) -> None:
37
+ """Validate composition without creating credentials or changing settings."""
38
+ if mode is AuthMode.NONE:
39
+ if not loopback:
40
+ raise RuntimeError(
41
+ 'Explicit WebUI no-auth mode requires a loopback listener'
42
+ )
43
+ if has_verifier or has_boundary or has_browser_sso:
44
+ raise RuntimeError('WebUI no-auth mode conflicts with configured identity')
45
+ if mode is AuthMode.EG and (not has_boundary or boundary_mode != 'eg'):
46
+ raise RuntimeError(
47
+ 'WebUI EG mode requires the host session boundary identified as eg'
48
+ )
49
+ if mode is AuthMode.OIDC and (
50
+ has_boundary or not has_verifier or not has_browser_sso
51
+ ):
52
+ raise RuntimeError(
53
+ 'WebUI OIDC mode requires its complete verifier and browser SSO, not an EG boundary'
54
+ )
55
+
56
+
57
+ @dataclass(frozen=True)
58
+ class AnonymousReadPolicy:
59
+ """Explicit exact read routes selected by trusted host composition.
60
+
61
+ No wildcard, mutation, direct workspace/configuration access or attended
62
+ browser control is admitted. Expanding those capabilities requires their
63
+ upstream anonymous policy/confirmation contract, not a fabricated grant.
64
+ """
65
+
66
+ routes: frozenset[str] = frozenset()
67
+
68
+ def __post_init__(self):
69
+ routes = self.routes
70
+ if type(routes) is not frozenset or any(
71
+ type(path) is not str
72
+ or not path.startswith('/api/')
73
+ or any(char in path for char in '*{}?%#')
74
+ or '..' in path
75
+ for path in routes
76
+ ):
77
+ raise ValueError('Anonymous read policy requires exact API paths')
78
+
79
+ def allows(self, method: str, path: str, *, admin: bool) -> bool:
80
+ reserved = (
81
+ '/api/enhanced',
82
+ '/api/files',
83
+ '/api/download',
84
+ '/api/config',
85
+ '/api/config-files',
86
+ '/api/editor-context',
87
+ '/api/browser',
88
+ '/api/mcp',
89
+ '/api/identity',
90
+ '/api/secrets',
91
+ )
92
+ return (
93
+ not admin
94
+ and method in {'GET', 'HEAD'}
95
+ and path in self.routes
96
+ and not any(
97
+ path == prefix or path.startswith(prefix + '/') for prefix in reserved
98
+ )
99
+ )
@@ -263,7 +263,7 @@ async def _deliver_with_deadline(
263
263
  timeout=_DELIVERY_TIMEOUT_SECONDS,
264
264
  )
265
265
  return ContactDeliveryResult.model_validate(raw_outcome, strict=True)
266
- except (ValidationError, asyncio.TimeoutError) as error:
266
+ except (TimeoutError, ValidationError) as error:
267
267
  logger.error(
268
268
  'Contact delivery outcome unknown: error_type=%s',
269
269
  type(error).__name__,
@@ -0,0 +1 @@
1
+ import{i as e,r as t,s as n}from"./bundle-mjs-DIyOrgL5.js";import{t as r}from"./createLucideIcon-DTQSidPf.js";import{t as i}from"./refresh-cw-BVhl5aJX.js";import{t as a}from"./server-CE-xbAAj.js";import{t as o}from"./badge-nQZ87mVE.js";import{E as s,S as c,a as l,c as u,f as d,w as f,x as p}from"./api-validation-CCoR_LRu.js";import{E as m,Jn as h,Nn as g,O as _,T as v,Un as y,Yt as b,Zn as x,ar as S,dn as C,dt as w,fr as ee,ft as te,k as T,mt as ne,or as re,rn as E,rr as ie,w as D,yn as ae,zn as O}from"./index-BL_57l7k.js";import{i as oe,n as k,r as se,t as ce}from"./tabs-A3rvoq-T.js";import{n as A}from"./identity-CwkFopGE.js";import{t as j}from"./unavailable-notice-B7WdWNor.js";import M from"./UserManagementView-xO_SUluQ.js";var N={name:`archive`,size:24,node:[[`rect`,{width:`20`,height:`5`,x:`2`,y:`3`,rx:`1`,key:`1wp1u1`}],[`path`,{d:`M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8`,key:`1s80jp`}],[`path`,{d:`M10 12h4`,key:`a56b0p`}]]};N.node;var le=r(N),P={name:`database-backup`,size:24,node:[[`ellipse`,{cx:`12`,cy:`5`,rx:`9`,ry:`3`,key:`msslwz`}],[`path`,{d:`M3 12a9 3 0 0 0 5 2.69`,key:`1ui2ym`}],[`path`,{d:`M21 9.3V5`,key:`6k6cib`}],[`path`,{d:`M3 5v14a9 3 0 0 0 6.47 2.88`,key:`i62tjy`}],[`path`,{d:`M12 12v4h4`,key:`1bxaet`}],[`path`,{d:`M13 20a5 5 0 0 0 9-3 4.5 4.5 0 0 0-4.5-4.5c-1.33 0-2.54.54-3.41 1.41L12 16`,key:`1f4ei9`}]]};P.node;var ue=r(P),F=n(e(),1),I=c({endpoint:s(),local:d(),reachable:d().optional(),breaker:s().optional()}),L=c({mode:u([`single`,`sharded`]),default_graph:s().optional(),endpoints:l(I)});function R(){return w(`/dashboard/daemon/shards`,L)}function z(){return w(`/dashboard/daemon/status`)}var B=c({total_nodes:p(),total_relationships:p(),available:d().optional(),source_graphs:l(s()).optional(),degraded_graphs:l(s()).optional(),partial:d().optional()}),V=c({by_type:f(s(),p()),type_count:p(),total_typed_nodes:p(),truncated:d(),available:d(),source_graphs:l(s()),degraded_graphs:l(s()),partial:d()}),H=c({source_systems:l(s())});function U(){return w(`/enhanced/graph/stats`,B)}function de(){return w(`/enhanced/graph/node-types`,V)}function fe(){return w(`/enhanced/code/instances`,H)}function pe(){return ne(`/configure`,{action:`backup_status`})}function me(){return te(`/graph/configure`,{action:`backup_create`})}var W=t();function G(e){return e===void 0?`-`:e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function he({stats:e,placement:t}){return(0,W.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-3 gap-4`,children:[(0,W.jsxs)(`div`,{className:`rounded border p-3`,children:[(0,W.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Nodes`}),(0,W.jsx)(`p`,{className:`text-2xl font-bold`,children:G(e?.total_nodes)})]}),(0,W.jsxs)(`div`,{className:`rounded border p-3`,children:[(0,W.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Relationships`}),(0,W.jsx)(`p`,{className:`text-2xl font-bold`,children:G(e?.total_relationships)})]}),(0,W.jsxs)(`div`,{className:`rounded border p-3`,children:[(0,W.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Shard placement`}),(0,W.jsx)(`p`,{className:`text-lg font-semibold`,children:t.length?`${String(t.length)} shard(s)`:`-`})]})]})}function ge({byType:e,nodeTypes:t}){return e.length===0?null:(0,W.jsxs)(`div`,{children:[(0,W.jsxs)(`p`,{className:`text-sm font-medium mb-2 flex items-center gap-1`,children:[(0,W.jsx)(x,{className:`size-3.5`}),`Counts by type`,(0,W.jsxs)(`span`,{className:`text-muted-foreground font-normal`,children:[`(`,G(t?.type_count),` types, `,G(t?.total_typed_nodes),` nodes)`]})]}),t?.partial===!0&&(0,W.jsxs)(`p`,{className:`mb-2 flex items-center gap-1.5 text-xs text-amber-500`,children:[(0,W.jsx)(C,{className:`size-3.5 shrink-0`}),`Partial — excludes `,t.degraded_graphs.join(`, `),`.`]}),(0,W.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:e.map(([e,t])=>(0,W.jsxs)(o,{variant:`outline`,className:`gap-1`,children:[e,(0,W.jsx)(`span`,{className:`text-muted-foreground`,children:G(t)})]},e))})]})}function _e(e){return e?.partial===!0?(0,W.jsxs)(`p`,{className:`flex items-center gap-1.5 text-xs text-amber-500`,children:[(0,W.jsx)(C,{className:`size-3.5 shrink-0`}),`These totals are partial — `,(e.degraded_graphs??[]).join(`, `),` could not be read.`]}):null}function ve(e){return e.length===0?null:(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`p`,{className:`text-sm font-medium mb-2`,children:`Placed on`}),(0,W.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:e.map(e=>(0,W.jsxs)(o,{variant:e.reachable?`default`:`destructive`,className:`font-mono text-xs gap-1`,children:[e.endpoint,e.local&&(0,W.jsx)(`span`,{className:`opacity-70`,children:`· local`})]},e.endpoint))})]})}function ye({defaultGraph:e,stats:t,placement:n,byType:r,nodeTypes:i}){return(0,W.jsxs)(D,{children:[(0,W.jsxs)(_,{children:[(0,W.jsxs)(T,{className:`text-base flex items-center gap-2`,children:[(0,W.jsx)(g,{className:`size-4`}),(0,W.jsx)(`span`,{className:`font-mono`,children:e}),(0,W.jsx)(o,{variant:`secondary`,children:`active`})]}),(0,W.jsx)(m,{children:`The active graph tenant served by this backend.`})]}),(0,W.jsxs)(v,{className:`space-y-4`,children:[he({stats:t,placement:n}),ge({byType:r,nodeTypes:i}),_e(t),ve(n)]})]})}function be({loading:e,sourcesUnavailable:t,sources:n}){return e?(0,W.jsx)(O,{className:`size-4 animate-spin text-muted-foreground`}):t?(0,W.jsx)(j,{what:`Indexed source tenants`}):n.length===0?(0,W.jsx)(`p`,{className:`text-muted-foreground text-sm`,children:`No indexed source tenants reported.`}):(0,W.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:n.map(e=>(0,W.jsx)(o,{variant:`secondary`,className:`font-mono text-xs`,children:e},e))})}function xe(){let[e,t]=(0,F.useState)(null),[n,r]=(0,F.useState)(null),[a,o]=(0,F.useState)(null),[s,c]=(0,F.useState)([]),[l,u]=(0,F.useState)(!1),[d,f]=(0,F.useState)(!1),p=async()=>{f(!0);let[e,n,i,a]=await Promise.all([U(),R(),fe(),de()]);t(e.ok?e.data:null),r(a.ok?a.data:null),o(n.ok?n.data:null),c(i.ok&&i.data?i.data.source_systems:[]),u(!i.ok),f(!1)};(0,F.useEffect)(()=>{p()},[]);let g=a?.default_graph??`__commons__`,y=a?.endpoints??[],b=Object.entries(n?.by_type??{}).sort((e,t)=>t[1]-e[1]);return(0,W.jsxs)(`div`,{className:`space-y-6`,"data-testid":`admin-tenants-panel`,children:[(0,W.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsxs)(`h2`,{className:`text-lg font-semibold flex items-center gap-2`,children:[(0,W.jsx)(ee,{className:`size-5`}),`Tenants & Graphs`]}),(0,W.jsx)(`p`,{className:`text-muted-foreground text-sm`,children:`Per-tenant node/edge counts and shard placement.`})]}),(0,W.jsxs)(E,{variant:`outline`,size:`sm`,onClick:()=>{p()},disabled:d,children:[(0,W.jsx)(i,{className:d?`size-4 animate-spin`:`size-4`}),(0,W.jsx)(`span`,{className:`ml-2`,children:`Refresh`})]})]}),ye({defaultGraph:g,stats:e,placement:y,byType:b,nodeTypes:n}),(0,W.jsxs)(D,{children:[(0,W.jsxs)(_,{children:[(0,W.jsxs)(T,{className:`text-base flex items-center gap-2`,children:[(0,W.jsx)(h,{className:`size-4`}),`Indexed source tenants`]}),(0,W.jsx)(m,{children:`Ingested source-systems that carry code in the graph.`})]}),(0,W.jsx)(v,{children:be({loading:d,sourcesUnavailable:l,sources:s})})]}),(0,W.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Note: full multi-tenant enumeration (a per-tenant catalog with per-tenant counts) is not yet exposed over the REST surface — the engine tenant catalog is reachable only over the UDS client. This panel shows the active graph with real statistics and shard placement plus indexed source tenants.`})]})}function Se(e){if(!e)return`outline`;let t=e.toLowerCase();return t===`closed`?`default`:t===`open`?`destructive`:`secondary`}function Ce({topology:e,endpoints:t,reachable:n}){return(0,W.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-4 gap-4`,children:[(0,W.jsx)(D,{children:(0,W.jsxs)(v,{className:`pt-6`,children:[(0,W.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Mode`}),(0,W.jsx)(`p`,{className:`text-2xl font-bold capitalize`,children:e?.mode??`-`})]})}),(0,W.jsx)(D,{children:(0,W.jsxs)(v,{className:`pt-6`,children:[(0,W.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Shards`}),(0,W.jsx)(`p`,{className:`text-2xl font-bold`,children:t.length||`-`})]})}),(0,W.jsx)(D,{children:(0,W.jsxs)(v,{className:`pt-6`,children:[(0,W.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Reachable`}),(0,W.jsx)(`p`,{className:`text-2xl font-bold`,children:t.length?`${String(n)}/${String(t.length)}`:`-`})]})}),(0,W.jsx)(D,{children:(0,W.jsxs)(v,{className:`pt-6`,children:[(0,W.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Default graph`}),(0,W.jsx)(`p`,{className:`text-lg font-semibold font-mono truncate`,children:e?.default_graph??`-`})]})})]})}function we(e,t){return(0,W.jsxs)(`div`,{className:`flex items-center justify-between rounded border p-3 text-sm`,children:[(0,W.jsxs)(`div`,{className:`flex items-center gap-3 min-w-0`,children:[(0,W.jsx)(a,{className:`size-4 shrink-0 text-muted-foreground`}),(0,W.jsxs)(`div`,{className:`flex flex-col min-w-0`,children:[(0,W.jsx)(`span`,{className:`font-mono truncate`,children:e.endpoint}),(0,W.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[`writer #`,t,` `,e.local?`· local`:`· remote`]})]})]}),(0,W.jsxs)(`div`,{className:`flex items-center gap-2 shrink-0`,children:[e.local&&(0,W.jsx)(o,{variant:`outline`,children:`local`}),e.breaker&&(0,W.jsx)(o,{variant:Se(e.breaker),className:`font-mono text-xs`,children:e.breaker}),e.reachable?(0,W.jsxs)(o,{variant:`default`,className:`gap-1`,children:[(0,W.jsx)(re,{className:`size-3`}),`up`]}):(0,W.jsxs)(o,{variant:`destructive`,className:`gap-1`,children:[(0,W.jsx)(S,{className:`size-3`}),`down`]})]})]},e.endpoint)}function Te(e){return(0,W.jsxs)(D,{children:[(0,W.jsxs)(_,{children:[(0,W.jsx)(T,{className:`text-base`,children:`Shards`}),(0,W.jsx)(m,{children:`Each configured engine endpoint and its live health.`})]}),(0,W.jsx)(v,{children:e.length===0?(0,W.jsx)(`p`,{className:`text-muted-foreground text-sm`,children:`No shard endpoints reported.`}):(0,W.jsx)(`div`,{className:`space-y-2`,children:e.map(we)})})]})}function Ee(e){return(0,W.jsxs)(`div`,{className:`flex flex-wrap gap-2 text-sm`,children:[e.role!==void 0&&(0,W.jsxs)(o,{variant:`secondary`,className:`gap-1`,children:[`role: `,e.role]}),(0,W.jsxs)(o,{variant:e.running?`default`:`outline`,className:`gap-1`,children:[e.running?(0,W.jsx)(O,{className:`size-3 animate-spin`}):(0,W.jsx)(S,{className:`size-3`}),e.running?`running`:`stopped`]}),e.queue_depth!==void 0&&(0,W.jsxs)(o,{variant:`secondary`,children:[`queue: `,String(e.queue_depth)]})]})}function De(e){return(0,W.jsxs)(D,{children:[(0,W.jsxs)(_,{children:[(0,W.jsx)(T,{className:`text-base`,children:`Daemon`}),(0,W.jsx)(m,{children:`The consolidated KG background daemon that hosts the local shard.`})]}),(0,W.jsx)(v,{children:e?Ee(e):(0,W.jsx)(`p`,{className:`text-muted-foreground text-sm`,children:`Daemon status unavailable.`})})]})}function Oe({unavailable:e,topologyError:t,topology:n,endpoints:r,reachable:i,daemon:a}){return e?(0,W.jsxs)(`p`,{className:`text-muted-foreground text-sm`,children:[`The `,(0,W.jsx)(`code`,{children:`/api/dashboard/daemon/shards`}),` route is not activated on this backend yet.`]}):t?(0,W.jsx)(j,{what:`Shard topology (${t})`}):(0,W.jsxs)(W.Fragment,{children:[Ce({topology:n,endpoints:r,reachable:i}),Te(r),De(a)]})}function ke(){let[e,t]=(0,F.useState)(null),[n,r]=(0,F.useState)(null),[a,s]=(0,F.useState)(!1),[c,l]=(0,F.useState)(null),[u,d]=(0,F.useState)(!1),f=async()=>{d(!0);let[e,n]=await Promise.all([R(),z()]);s(e.unavailable),l(!e.ok&&!e.unavailable?e.error??`The shard topology request failed.`:null),t(e.ok?e.data:null),r(n.ok?n.data:null),d(!1)};(0,F.useEffect)(()=>{f()},[]);let p=e?.endpoints??[],m=p.filter(e=>e.reachable).length;return(0,W.jsxs)(`div`,{className:`space-y-6`,"data-testid":`admin-shards-panel`,children:[(0,W.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsxs)(`h2`,{className:`text-lg font-semibold flex items-center gap-2`,children:[(0,W.jsx)(y,{className:`size-5`}),`Shard Topology`,e&&(0,W.jsx)(o,{variant:`secondary`,className:`uppercase`,children:e.mode})]}),(0,W.jsx)(`p`,{className:`text-muted-foreground text-sm`,children:`K-way writer layout, per-shard reachability and circuit-breaker state.`})]}),(0,W.jsxs)(E,{variant:`outline`,size:`sm`,onClick:()=>{f()},disabled:u,children:[(0,W.jsx)(i,{className:u?`size-4 animate-spin`:`size-4`}),(0,W.jsx)(`span`,{className:`ml-2`,children:`Refresh`})]})]}),Oe({unavailable:a,topologyError:c,topology:e,endpoints:p,reachable:m,daemon:n})]})}function Ae(e){if(e===void 0)return`-`;let t=[`B`,`KB`,`MB`,`GB`,`TB`],n=e,r=0;for(;n>=1024&&r<t.length-1;)n/=1024,r++;return`${n.toFixed(1)} ${t[r]}`}function je(){let[e,t]=(0,F.useState)(null),[n,r]=(0,F.useState)(!1),[i,a]=(0,F.useState)(!1),[o,s]=(0,F.useState)(!1),c=async()=>{a(!0);let e=await pe();r(!e.ok),t(e.ok?e.data:null),a(!1)};return(0,F.useEffect)(()=>{c()},[]),{status:e,loading:i,triggering:o,wired:!n,refresh:c,onTrigger:async()=>{s(!0),await me(),await c(),s(!1)}}}function Me({loading:e,triggering:t,wired:n,onRefresh:r,onTrigger:a}){return(0,W.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,W.jsxs)(E,{variant:`outline`,size:`sm`,onClick:r,disabled:e,children:[(0,W.jsx)(i,{className:e?`size-4 animate-spin`:`size-4`}),(0,W.jsx)(`span`,{className:`ml-2`,children:`Refresh`})]}),(0,W.jsxs)(E,{size:`sm`,onClick:a,disabled:!n||t,title:n?`Trigger an online backup`:`Backup REST twin not wired yet`,children:[t?(0,W.jsx)(O,{className:`size-4 animate-spin`}):(0,W.jsx)(le,{className:`size-4`}),(0,W.jsx)(`span`,{className:`ml-2`,children:`Trigger backup`})]})]})}function Ne(){return(0,W.jsxs)(D,{className:`border-dashed`,children:[(0,W.jsxs)(_,{children:[(0,W.jsxs)(T,{className:`text-base flex items-center gap-2`,children:[(0,W.jsx)(o,{variant:`outline`,children:`read-only · not wired`}),`Backup/PITR not exposed over REST yet`]}),(0,W.jsxs)(m,{children:[`Online backup / restore (EG-090) is reachable today only over the epistemic-graph UDS client (a`,(0,W.jsx)(`code`,{children:` Method::Backup`}),` op streaming a per-shard MVCC snapshot). This panel will list snapshots, show the PITR window, and enable the trigger control as soon as the REST twin is wired; until then it is read-only by design and shows no fabricated backups.`]})]}),(0,W.jsxs)(v,{className:`text-sm text-muted-foreground space-y-2`,children:[(0,W.jsx)(`p`,{className:`font-medium text-foreground`,children:`The engine backup model:`}),(0,W.jsxs)(`ul`,{className:`list-disc pl-5 space-y-1`,children:[(0,W.jsx)(`li`,{children:`Online per-shard MVCC snapshot streamed verbatim (no write-stall).`}),(0,W.jsx)(`li`,{children:`Point-in-time restore to a chosen LSN / timestamp within the retained window.`})]})]})]})}function Pe({status:e,backupCount:t}){return(0,W.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-3 gap-4`,children:[(0,W.jsx)(D,{children:(0,W.jsxs)(v,{className:`pt-6`,children:[(0,W.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Snapshots`}),(0,W.jsx)(`p`,{className:`text-2xl font-bold`,children:t})]})}),(0,W.jsx)(D,{children:(0,W.jsxs)(v,{className:`pt-6`,children:[(0,W.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Last backup`}),(0,W.jsx)(`p`,{className:`text-lg font-semibold`,children:e?.last_backup_at??`-`})]})}),(0,W.jsx)(D,{children:(0,W.jsxs)(v,{className:`pt-6`,children:[(0,W.jsxs)(`p`,{className:`text-sm text-muted-foreground flex items-center gap-1`,children:[(0,W.jsx)(ie,{className:`size-3.5`}),`PITR window`]}),(0,W.jsxs)(`p`,{className:`text-xs font-mono`,children:[e?.pitr_window?.earliest??`-`,` → `,e?.pitr_window?.latest??`-`]})]})})]})}function Fe({backup:e}){return(0,W.jsxs)(`div`,{className:`flex items-center justify-between rounded border p-2 text-sm`,children:[(0,W.jsxs)(`div`,{className:`flex flex-col min-w-0`,children:[(0,W.jsx)(`span`,{className:`font-mono truncate`,children:e.id}),(0,W.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[e.created_at??`-`,` `,e.shard?`· ${e.shard}`:``,` `,e.lsn?`· LSN ${e.lsn}`:``]})]}),(0,W.jsx)(o,{variant:`secondary`,children:Ae(e.size_bytes)})]})}function Ie({backups:e}){return(0,W.jsxs)(D,{children:[(0,W.jsxs)(_,{children:[(0,W.jsx)(T,{className:`text-base`,children:`Snapshots`}),(0,W.jsx)(m,{children:`Retained backups available for point-in-time restore.`})]}),(0,W.jsx)(v,{children:e.length===0?(0,W.jsx)(`p`,{className:`text-muted-foreground text-sm`,children:`No snapshots yet.`}):(0,W.jsx)(`div`,{className:`space-y-2`,children:e.map(e=>(0,W.jsx)(Fe,{backup:e},e.id))})})]})}function Le({loading:e,wired:t,status:n,backups:r}){return e?(0,W.jsx)(O,{className:`size-5 animate-spin text-muted-foreground`}):t?(0,W.jsxs)(W.Fragment,{children:[(0,W.jsx)(Pe,{status:n,backupCount:r.length}),(0,W.jsx)(Ie,{backups:r})]}):(0,W.jsx)(Ne,{})}function Re(){let e=je(),t=e.status?.backups??[];return(0,W.jsxs)(`div`,{className:`space-y-6`,"data-testid":`admin-backup-panel`,children:[(0,W.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsxs)(`h2`,{className:`text-lg font-semibold flex items-center gap-2`,children:[(0,W.jsx)(ue,{className:`size-5`}),`Backup & PITR`]}),(0,W.jsx)(`p`,{className:`text-muted-foreground text-sm`,children:`Online backups and point-in-time restore (CONCEPT:EG-090).`})]}),(0,W.jsx)(Me,{loading:e.loading,triggering:e.triggering,wired:e.wired,onRefresh:()=>{e.refresh()},onTrigger:()=>{e.onTrigger()}})]}),(0,W.jsx)(Le,{loading:e.loading,wired:e.wired,status:e.status,backups:t})]})}var K=[[`idle_ms`,`Idle timeout`],[`absolute_ms`,`Absolute lifetime`],[`privileged_idle_ms`,`Privileged idle timeout`],[`privileged_absolute_ms`,`Privileged absolute lifetime`]];function ze(e){return Object.values(e).every(e=>Number.isInteger(e)&&e>=6e4&&e<=2592e6)}function q(e,t){return e===void 0||t===void 0||e<=t}function Be(e){return ze(e)&&q(e.idle_ms,e.absolute_ms)&&q(e.privileged_idle_ms,e.idle_ms)&&q(e.privileged_absolute_ms,e.absolute_ms)&&q(e.privileged_idle_ms,e.privileged_absolute_ms)}function Ve(e){return Object.fromEntries(K.flatMap(([t])=>e[t]===void 0?[]:[[t,e[t]]]))}function He(e,t){return Object.fromEntries(K.flatMap(([n])=>e[n]===t[n]?[]:[[n,e[n]]]))}function Ue({field:e,label:t,valueMs:n,onChangeMs:r}){return(0,W.jsxs)(`div`,{children:[(0,W.jsxs)(`label`,{className:`block text-sm`,htmlFor:e,children:[t,` (minutes)`]}),(0,W.jsx)(b,{id:e,type:`number`,min:1,max:43200,value:Math.round(n/6e4),onChange:e=>{r(Number(e.target.value)*6e4)}})]})}function We(e,t){return!Number.isInteger(e)||e<8||e>256||!Be(t)}function Ge({registration:e,setRegistration:t,fallback:n,setFallback:r,minimum:i,setMinimum:a,durations:o,setDurations:s,onSave:c}){return(0,W.jsxs)(W.Fragment,{children:[(0,W.jsx)(`label`,{className:`block text-sm`,htmlFor:`registration-policy`,children:`Registration`}),(0,W.jsxs)(`select`,{id:`registration-policy`,className:`rounded border bg-background p-2`,value:e,onChange:e=>{t(e.target.value)},children:[(0,W.jsx)(`option`,{value:`disabled`,children:`Disabled`}),(0,W.jsx)(`option`,{value:`admin_only`,children:`Administrator only`}),(0,W.jsx)(`option`,{value:`invite`,children:`Invitation`}),(0,W.jsx)(`option`,{value:`open`,children:`Open`})]}),(0,W.jsx)(`label`,{className:`block text-sm`,htmlFor:`policy-fallback`,children:`Local fallback`}),(0,W.jsxs)(`select`,{id:`policy-fallback`,className:`rounded border bg-background p-2`,value:n,onChange:e=>{r(e.target.value)},children:[(0,W.jsx)(`option`,{value:`off`,children:`Off`}),(0,W.jsx)(`option`,{value:`break_glass`,children:`Break glass only`}),(0,W.jsx)(`option`,{value:`full`,children:`Full`})]}),(0,W.jsx)(`label`,{className:`block text-sm`,htmlFor:`password-minimum`,children:`Minimum password length`}),(0,W.jsx)(b,{id:`password-minimum`,type:`number`,min:8,max:256,value:i,onChange:e=>{a(Number(e.target.value))}}),K.map(([e,t])=>{let n=o[e];return n===void 0?null:(0,W.jsx)(Ue,{field:e,label:t,valueMs:n,onChangeMs:t=>{s(n=>({...n,[e]:t}))}},e)}),(0,W.jsx)(E,{type:`button`,disabled:We(i,o),onClick:c,children:`Save identity policy`})]})}function Ke(){let[e,t]=(0,F.useState)(null),[n,r]=(0,F.useState)(`disabled`),[i,a]=(0,F.useState)(`break_glass`),[o,s]=(0,F.useState)(12),[c,l]=(0,F.useState)({}),[u,d]=(0,F.useState)(null),f=e=>{t(e),e.kind===`ready`&&(r(e.result.registration_policy),a(e.result.local_fallback),s(e.result.password_min_chars),l(Ve(e.result)))};(0,F.useEffect)(()=>{let e=!0;return A(`identity.policy.get`).then(t=>{e&&f(t)}),()=>{e=!1}},[]);let p=async()=>{if(e?.kind!==`ready`)return;let r=await A(`identity.policy.set`,{expected_epoch:e.result.epoch,registration_policy:n,local_fallback:i,password_min_chars:o,...He(c,e.result)});d(r),r.kind===`ready`&&t(r)};return(0,W.jsxs)(D,{children:[(0,W.jsxs)(_,{children:[(0,W.jsx)(T,{children:`Identity policy`}),(0,W.jsx)(m,{children:`Policy changes use the current configuration epoch and require fresh MFA.`})]}),(0,W.jsxs)(v,{className:`space-y-3`,children:[e===null&&(0,W.jsx)(`p`,{role:`status`,children:`Loading identity policy…`}),e!==null&&e.kind!==`ready`&&(0,W.jsx)(`p`,{role:`status`,children:e.message}),e?.kind===`ready`&&(0,W.jsx)(Ge,{registration:n,setRegistration:r,fallback:i,setFallback:a,minimum:o,setMinimum:s,durations:c,setDurations:l,onSave:()=>{p()}}),Object.keys(c).length>0&&(0,W.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Changing a session duration revokes existing sessions immediately.`}),(0,W.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`MFA policy editing is unavailable until the engine exposes those fields.`}),u&&(0,W.jsx)(`p`,{role:`status`,children:u.kind===`ready`?`Identity policy saved.`:u.message})]})]})}function J(e,t){return(e===`identity.sessions.list`||e===`identity.api_keys.list`)&&!t}function qe(e,t){return e.principal_id??e.id??e.handle??e.key_id??t}function Je(e,t){return e.name??e.username??e.principal_id??e.id??e.handle??e.key_id??`Record ${t+1}`}function Y(e){return e.handle??e.id??e.key_id??``}function Ye({item:e,index:t,revokeOp:n,onRevoke:r}){return(0,W.jsxs)(`li`,{className:`rounded border p-2`,children:[(0,W.jsx)(`strong`,{children:Je(e,t)}),e.status&&(0,W.jsx)(`span`,{className:`ml-2 text-muted-foreground`,children:e.status}),e.description&&(0,W.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:e.description}),n&&Y(e)&&(0,W.jsx)(E,{type:`button`,size:`sm`,variant:`outline`,className:`ml-2`,onClick:()=>{r(Y(e))},children:`Revoke`})]})}function Xe({state:e,revokeOp:t,loadingHint:n,onRevoke:r,onLoadMore:i}){return e===null?(0,W.jsx)(`p`,{role:`status`,children:n}):e.kind===`ready`?Array.isArray(e.result.items)?e.result.items.length===0?(0,W.jsx)(`p`,{role:`status`,children:`No records reported.`}):(0,W.jsxs)(W.Fragment,{children:[(0,W.jsx)(`ul`,{className:`space-y-2`,children:e.result.items.map((e,n)=>(0,W.jsx)(Ye,{item:e,index:n,revokeOp:t,onRevoke:r},qe(e,n)))}),e.result.next_cursor&&(0,W.jsx)(E,{type:`button`,variant:`outline`,onClick:i,children:`Load more`})]}):(0,W.jsx)(`p`,{role:`alert`,children:`The identity service returned an invalid list.`}):(0,W.jsx)(`p`,{role:`status`,children:e.message})}function Ze(e,t){let[n,r]=(0,F.useState)(null),[i,a]=(0,F.useState)(0),[o,s]=(0,F.useState)(null);return(0,F.useEffect)(()=>{let n=!0;return J(e,t)?()=>void 0:(A(e,{...e===`identity.audit.list`||e===`identity.api_keys.list`?{limit:50}:{},...t?{principal_id:t}:{}}).then(e=>{n&&r(e)}),()=>{n=!1})},[e,t,i]),{state:n,mutation:o,revoke:async(e,t)=>{if(!e)return;let n=await A(e,{id:t});s(n),n.kind===`ready`&&a(e=>e+1)},loadMore:async()=>{if(n?.kind!==`ready`||!n.result.next_cursor)return;let i=await A(e,{after:n.result.next_cursor,limit:50,...t?{principal_id:t}:{}});i.kind===`ready`?r({kind:`ready`,result:{items:[...n.result.items,...i.result.items],next_cursor:i.result.next_cursor}}):s(i)},refresh:()=>{a(e=>e+1)}}}function X({title:e,op:t,description:n,principalId:r,revokeOp:i}){let a=Ze(t,r),o=J(t,r)?`Enter a principal id to inspect its records.`:`Loading…`;return(0,W.jsxs)(D,{children:[(0,W.jsxs)(_,{children:[(0,W.jsx)(T,{children:e}),(0,W.jsx)(m,{children:n})]}),(0,W.jsxs)(v,{children:[r&&(0,W.jsxs)(`p`,{className:`mb-2 text-xs text-muted-foreground`,children:[`Principal: `,r]}),a.state!==null&&(0,W.jsx)(E,{type:`button`,size:`sm`,variant:`outline`,className:`mb-3`,onClick:a.refresh,children:`Refresh`}),(0,W.jsx)(Xe,{state:a.state,revokeOp:i,loadingHint:o,onRevoke:e=>{a.revoke(i,e)},onLoadMore:()=>{a.loadMore()}}),a.mutation&&(0,W.jsx)(`p`,{role:`status`,children:a.mutation.kind===`ready`?`Revocation confirmed.`:a.mutation.message})]})]})}function Z({kind:e}){let[t,n]=(0,F.useState)(``),[r,i]=(0,F.useState)(``);return(0,W.jsxs)(`div`,{className:`space-y-3`,children:[(0,W.jsxs)(`form`,{className:`flex gap-2`,onSubmit:e=>{e.preventDefault(),i(t.trim())},children:[(0,W.jsx)(b,{"aria-label":`${e===`sessions`?`Session`:`API key`} principal id`,placeholder:`Principal id`,value:t,onChange:e=>{n(e.target.value)}}),(0,W.jsxs)(E,{type:`submit`,disabled:!t.trim(),children:[`Load `,e]})]}),(0,W.jsx)(X,{title:e===`sessions`?`Sessions`:`API keys`,op:e===`sessions`?`identity.sessions.list`:`identity.api_keys.list`,principalId:r,revokeOp:e===`sessions`?`identity.sessions.revoke`:`identity.api_keys.revoke`,description:e===`sessions`?`Sessions for the selected principal.`:`Metadata only; secrets are never displayed.`})]})}function Q({kind:e}){let[t,n]=(0,F.useState)(``),[r,i]=(0,F.useState)(``),[a,o]=(0,F.useState)(``),[s,c]=(0,F.useState)(``),[l,u]=(0,F.useState)(`add`),[d,f]=(0,F.useState)(null),[p,h]=(0,F.useState)(!1),g=e===`group`,y=g?`Group`:`Role`,x=async()=>{h(!0);let e=a.split(`,`).map(e=>e.trim()).filter(Boolean);f(await A(g?`identity.groups.upsert`:`identity.roles.upsert`,g?{group_id:t,name:r,roles:e}:{role_id:t,name:r,scopes:e})),h(!1)},S=async()=>{h(!0),f(await A(g?`identity.groups.change_membership`:`identity.roles.change_user_role`,g?{principal_id:s,group_id:t,change:l}:{principal_id:s,role_id:t,change:l})),h(!1)};return(0,W.jsxs)(D,{children:[(0,W.jsxs)(_,{children:[(0,W.jsxs)(T,{children:[y,` administration`]}),(0,W.jsx)(m,{children:`Writes require administrator authority and fresh MFA.`})]}),(0,W.jsxs)(v,{className:`space-y-3`,children:[(0,W.jsxs)(`div`,{className:`grid gap-2 sm:grid-cols-3`,children:[(0,W.jsx)(b,{"aria-label":`${y} id`,placeholder:`${y} id`,value:t,onChange:e=>{n(e.target.value)}}),(0,W.jsx)(b,{"aria-label":`${y} name`,placeholder:`Display name`,value:r,onChange:e=>{i(e.target.value)}}),(0,W.jsx)(b,{"aria-label":g?`Group roles`:`Role scopes`,placeholder:g?`Roles, comma separated`:`Scopes, comma separated`,value:a,onChange:e=>{o(e.target.value)}})]}),(0,W.jsxs)(E,{type:`button`,disabled:p||!t.trim()||!r.trim(),onClick:()=>{x()},children:[`Save `,y.toLowerCase()]}),(0,W.jsxs)(`div`,{className:`flex flex-wrap gap-2 border-t pt-3`,children:[(0,W.jsx)(b,{"aria-label":`Member principal id`,className:`max-w-xs`,placeholder:`Principal id`,value:s,onChange:e=>{c(e.target.value)}}),(0,W.jsxs)(`select`,{"aria-label":`Membership action`,className:`rounded border bg-background p-2`,value:l,onChange:e=>{u(e.target.value)},children:[(0,W.jsx)(`option`,{value:`add`,children:`Add`}),(0,W.jsx)(`option`,{value:`remove`,children:`Remove`})]}),(0,W.jsx)(E,{type:`button`,disabled:p||!t.trim()||!s.trim(),onClick:()=>{S()},children:`Apply membership`})]}),d&&(0,W.jsx)(`p`,{role:`status`,children:d.kind===`ready`?`${y} change confirmed. Refresh the list.`:d.message})]})]})}function Qe(){let[e,t]=(0,F.useState)(``),[n,r]=(0,F.useState)(`{"groups":[]}`),[i,a]=(0,F.useState)(null),o=async()=>{try{let t=JSON.parse(n);if(!t||typeof t!=`object`||Array.isArray(t))throw Error(`Claims must be an object`);if(!Object.values(t).every(e=>Array.isArray(e)&&e.every(e=>typeof e==`string`)))throw Error(`Every claim must be a string array`);a(await A(`identity.idps.mapping_dry_run`,{idp_id:e,claims:t}))}catch{a({kind:`error`,message:`Enter a JSON object whose values are string arrays.`})}};return(0,W.jsxs)(D,{children:[(0,W.jsxs)(_,{children:[(0,W.jsx)(T,{children:`Mapping rule dry run`}),(0,W.jsx)(m,{children:`Preview the roles, groups and scopes a sample claim set would receive. This does not change an identity.`})]}),(0,W.jsxs)(v,{className:`space-y-3`,children:[(0,W.jsx)(b,{"aria-label":`Identity provider id`,placeholder:`Identity provider id`,value:e,onChange:e=>{t(e.target.value)}}),(0,W.jsx)(`textarea`,{"aria-label":`Sample claims JSON`,className:`w-full rounded border bg-background p-2 font-mono text-sm`,rows:4,value:n,onChange:e=>{r(e.target.value)}}),(0,W.jsx)(E,{type:`button`,disabled:!e.trim(),onClick:()=>{o()},children:`Evaluate mapping`}),i?.kind!==`ready`&&i!==null&&(0,W.jsx)(`p`,{role:`status`,children:i.message}),i?.kind===`ready`&&(0,W.jsxs)(`dl`,{className:`text-sm space-y-1`,children:[(0,W.jsx)(`dt`,{children:`Roles`}),(0,W.jsx)(`dd`,{children:i.result.roles.join(`, `)||`None`}),(0,W.jsx)(`dt`,{children:`Groups`}),(0,W.jsx)(`dd`,{children:i.result.groups.join(`, `)||`None`}),(0,W.jsx)(`dt`,{children:`Scopes`}),(0,W.jsx)(`dd`,{children:i.result.scopes.join(`, `)||`None`})]})]})]})}function $(){let[e,t]=(0,F.useState)(``),[n,r]=(0,F.useState)(``),[i,a]=(0,F.useState)(`oidc`),[o,s]=(0,F.useState)(`{}`),[c,l]=(0,F.useState)(``),[u,d]=(0,F.useState)(null),f=async()=>{try{let t=JSON.parse(o);if(!t||typeof t!=`object`||Array.isArray(t))throw Error(`Invalid configuration`);d(await A(`identity.idps.upsert`,{idp_id:e.trim(),kind:i,display_name:n.trim(),enabled:!1,config_json:o,jit_policy:`deny`,...c.trim()?{secret_ref:c.trim()}:{}}))}catch{d({kind:`error`,message:`Configuration must be a JSON object.`})}};return(0,W.jsxs)(D,{children:[(0,W.jsxs)(_,{children:[(0,W.jsx)(T,{children:`Configure identity provider`}),(0,W.jsx)(m,{children:`Use a secret reference; do not paste credentials. New providers start disabled with just-in-time provisioning denied until mapping rules are reviewed.`})]}),(0,W.jsxs)(v,{className:`space-y-3`,children:[(0,W.jsxs)(`div`,{className:`grid gap-2 sm:grid-cols-2`,children:[(0,W.jsx)(b,{"aria-label":`Provider id`,placeholder:`Provider id`,value:e,onChange:e=>{t(e.target.value)}}),(0,W.jsx)(b,{"aria-label":`Provider display name`,placeholder:`Display name`,value:n,onChange:e=>{r(e.target.value)}})]}),(0,W.jsxs)(`select`,{"aria-label":`Provider kind`,className:`rounded border bg-background p-2`,value:i,onChange:e=>{a(e.target.value)},children:[(0,W.jsx)(`option`,{value:`oidc`,children:`OIDC`}),(0,W.jsx)(`option`,{value:`saml`,children:`SAML`}),(0,W.jsx)(`option`,{value:`ldap`,children:`LDAP`}),(0,W.jsx)(`option`,{value:`scim`,children:`SCIM`})]}),(0,W.jsx)(b,{"aria-label":`Provider secret reference`,placeholder:`Secret reference (optional)`,value:c,onChange:e=>{l(e.target.value)}}),(0,W.jsx)(`textarea`,{"aria-label":`Provider configuration JSON`,className:`w-full rounded border bg-background p-2 font-mono text-sm`,rows:5,value:o,onChange:e=>{s(e.target.value)}}),(0,W.jsx)(E,{type:`button`,disabled:!e.trim()||!n.trim(),onClick:()=>{f()},children:`Save provider`}),u&&(0,W.jsx)(`p`,{role:`status`,children:u.kind===`ready`?`Provider saved. Refresh the list.`:u.message})]})]})}function $e(){let[e,t]=(0,F.useState)(null),[n,r]=(0,F.useState)(``),[i,a]=(0,F.useState)(`break_glass`),[o,s]=(0,F.useState)(!1),[c,l]=(0,F.useState)(null);return(0,F.useEffect)(()=>{let e=!0;return A(`identity.mode.status`).then(n=>{e&&t(n)}),()=>{e=!1}},[]),{state:e,target:n,setTarget:r,fallback:i,setFallback:a,acknowledged:o,setAcknowledged:s,transition:c,submit:async()=>{let e=await A(`identity.mode.transition`,n===`external`?{to:n,local_fallback:i}:{to:n});l(e),e.kind===`ready`&&t(await A(`identity.mode.status`))}}}function et(e,t,n){return!e||!t||n?.kind!==`ready`||t===n.result.mode}function tt(){let e=$e();return(0,W.jsxs)(D,{children:[(0,W.jsxs)(_,{children:[(0,W.jsx)(T,{children:`Security mode`}),(0,W.jsx)(m,{children:`Mode transitions require a fresh MFA administrator session. A successful transition revokes existing sessions.`})]}),(0,W.jsxs)(v,{className:`space-y-3`,children:[e.state===null&&(0,W.jsx)(`p`,{role:`status`,children:`Loading mode…`}),e.state!==null&&e.state.kind!==`ready`&&(0,W.jsx)(`p`,{role:`status`,children:e.state.message}),e.state?.kind===`ready`&&(0,W.jsxs)(`p`,{children:[`Current mode: `,(0,W.jsx)(`strong`,{children:e.state.result.mode})]}),(0,W.jsx)(`label`,{className:`block text-sm`,htmlFor:`target-mode`,children:`Target mode`}),(0,W.jsxs)(`select`,{id:`target-mode`,className:`rounded border bg-background p-2`,value:e.target,onChange:t=>{e.setTarget(t.target.value)},children:[(0,W.jsx)(`option`,{value:``,children:`Select a mode`}),(0,W.jsx)(`option`,{value:`local`,children:`Local`}),(0,W.jsx)(`option`,{value:`external`,children:`External`})]}),e.target===`external`&&(0,W.jsxs)(`select`,{"aria-label":`Local fallback`,className:`rounded border bg-background p-2`,value:e.fallback,onChange:t=>{e.setFallback(t.target.value)},children:[(0,W.jsx)(`option`,{value:`off`,children:`No local fallback`}),(0,W.jsx)(`option`,{value:`break_glass`,children:`Break glass only`}),(0,W.jsx)(`option`,{value:`full`,children:`Full local fallback`})]}),(0,W.jsxs)(`label`,{className:`flex items-center gap-2 text-sm`,children:[(0,W.jsx)(`input`,{type:`checkbox`,checked:e.acknowledged,onChange:t=>{e.setAcknowledged(t.target.checked)}}),`I understand this transition revokes current sessions.`]}),(0,W.jsx)(E,{type:`button`,disabled:et(e.acknowledged,e.target,e.state),onClick:()=>{e.submit()},children:`Request transition`}),e.transition&&(0,W.jsx)(`p`,{role:`status`,children:e.transition.kind===`ready`?`Transition completed. Sign in again.`:e.transition.message})]})]})}function nt(){let[e,t]=(0,F.useState)(!1),[n,r]=(0,F.useState)(null),i=async()=>{r(await A(`identity.issuer.rotate`))};return(0,W.jsxs)(D,{children:[(0,W.jsxs)(_,{children:[(0,W.jsx)(T,{children:`Issuer key rotation`}),(0,W.jsx)(m,{children:`Rotate the Arbora signer with overlap. A fresh administrator MFA confirmation is required.`})]}),(0,W.jsxs)(v,{className:`space-y-3`,children:[(0,W.jsxs)(`label`,{className:`flex items-center gap-2 text-sm`,children:[(0,W.jsx)(`input`,{type:`checkbox`,checked:e,onChange:e=>{t(e.target.checked)}}),`I understand issuer rotation changes the signing key.`]}),(0,W.jsx)(E,{type:`button`,disabled:!e,onClick:()=>{i()},children:`Request issuer rotation`}),n&&(0,W.jsx)(`p`,{role:`status`,children:n.kind===`ready`?`Issuer key rotated (epoch ${n.result.epoch}, key ${n.result.issuer_kid_current}).`:n.message})]})]})}function rt(){let[e,t]=(0,F.useState)(``),[n,r]=(0,F.useState)(``),[i,a]=(0,F.useState)(null),[o,s]=(0,F.useState)(null),c=async()=>{a(await A(`identity.scim_clients.list`))};(0,F.useEffect)(()=>{c()},[]);let l=async()=>{let t=await A(`identity.scim_clients.upsert`,{idp_id:e.trim(),principal_id:n.trim()});s(t),t.kind===`ready`&&c()},u=async e=>{let t=await A(`identity.scim_clients.remove`,{idp_id:e});s(t),t.kind===`ready`&&c()};return(0,W.jsxs)(D,{children:[(0,W.jsxs)(_,{children:[(0,W.jsx)(T,{children:`SCIM clients`}),(0,W.jsx)(m,{children:`Bind an enabled SCIM provider to an active service principal.`})]}),(0,W.jsxs)(v,{className:`space-y-3`,children:[i===null&&(0,W.jsx)(`p`,{role:`status`,children:`Loading SCIM clients…`}),i&&i.kind!==`ready`&&(0,W.jsx)(`p`,{role:`status`,children:i.message}),i?.kind===`ready`&&(0,W.jsx)(`ul`,{className:`space-y-2`,children:i.result.items.map(e=>(0,W.jsxs)(`li`,{className:`flex items-center justify-between rounded border p-2`,children:[(0,W.jsxs)(`span`,{children:[e.idp_id,`: `,(0,W.jsx)(`code`,{children:e.principal_id}),` (`,e.enabled?`enabled`:`disabled`,`)`]}),(0,W.jsx)(E,{type:`button`,variant:`outline`,size:`sm`,onClick:()=>{u(e.idp_id)},children:`Remove`})]},e.idp_id))}),(0,W.jsx)(b,{"aria-label":`SCIM provider id`,placeholder:`Provider id`,value:e,onChange:e=>{t(e.target.value)}}),(0,W.jsx)(b,{"aria-label":`SCIM service principal id`,placeholder:`Service principal id`,value:n,onChange:e=>{r(e.target.value)}}),(0,W.jsx)(E,{type:`button`,disabled:!e.trim()||!n.trim(),onClick:()=>{l()},children:`Bind SCIM client`}),o&&(0,W.jsx)(`p`,{role:`status`,children:o.kind===`ready`?`SCIM client change confirmed.`:o.message})]})]})}function it(){let[e,t]=(0,F.useState)(null),[n,r]=(0,F.useState)(null),i=async()=>{t(await A(`identity.audit.verify`))},a=async()=>{let e=await A(`identity.audit.export`,{limit:500});if(r(e),e.kind!==`ready`)return;let t=URL.createObjectURL(new Blob([JSON.stringify(e.result,null,2)],{type:`application/json`})),n=document.createElement(`a`);n.href=t,n.download=`identity-audit-page.json`,n.click(),URL.revokeObjectURL(t)};return(0,W.jsxs)(`div`,{className:`space-y-4`,children:[(0,W.jsx)(X,{title:`Identity audit`,op:`identity.audit.list`,description:`Identity administration events.`}),(0,W.jsxs)(D,{children:[(0,W.jsxs)(_,{children:[(0,W.jsx)(T,{children:`Audit integrity and export`}),(0,W.jsx)(m,{children:`Verify the chain or export a bounded page with its continuation cursor.`})]}),(0,W.jsxs)(v,{className:`space-y-2`,children:[(0,W.jsxs)(`div`,{className:`flex gap-2`,children:[(0,W.jsx)(E,{type:`button`,variant:`outline`,onClick:()=>{i()},children:`Verify audit chain`}),(0,W.jsx)(E,{type:`button`,variant:`outline`,onClick:()=>{a()},children:`Export first audit page`})]}),e&&(0,W.jsx)(`p`,{role:`status`,children:e.kind===`ready`?e.result.valid?`Audit chain verified.`:`Audit chain broken at sequence ${e.result.first_broken_seq??`unknown`}.`:e.message}),n&&n.kind!==`ready`&&(0,W.jsx)(`p`,{role:`status`,children:n.message})]})]})]})}function at(){return(0,W.jsxs)(`div`,{className:`space-y-6`,"data-testid":`admin-view`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsxs)(`h1`,{className:`text-2xl font-bold flex items-center gap-2`,children:[(0,W.jsx)(ae,{className:`size-6`}),`Admin Console`]}),(0,W.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Arbora identity, security and engine administration.`})]}),(0,W.jsxs)(ce,{defaultValue:`users`,children:[(0,W.jsx)(se,{className:`flex h-auto flex-wrap justify-start`,children:[`users`,`service-accounts`,`groups`,`roles`,`idps`,`sessions`,`api-keys`,`audit`,`security-mode`,`policy`,`tenants`,`shards`,`backup`].map(e=>(0,W.jsx)(oe,{value:e,children:e.replaceAll(`-`,` `)},e))}),(0,W.jsx)(k,{value:`users`,children:(0,W.jsx)(M,{})}),(0,W.jsx)(k,{value:`service-accounts`,children:(0,W.jsx)(X,{title:`Service accounts`,op:`identity.service_accounts.list`,description:`Active service principals from Arbora identity.`})}),(0,W.jsxs)(k,{value:`groups`,className:`space-y-4`,children:[(0,W.jsx)(X,{title:`Groups`,op:`identity.groups.list`,description:`Groups and memberships from Arbora identity.`}),(0,W.jsx)(Q,{kind:`group`})]}),(0,W.jsxs)(k,{value:`roles`,className:`space-y-4`,children:[(0,W.jsx)(X,{title:`Roles and scopes`,op:`identity.roles.list`,description:`Roles and effective scope grants from Arbora identity.`}),(0,W.jsx)(Q,{kind:`role`})]}),(0,W.jsxs)(k,{value:`idps`,className:`space-y-4`,children:[(0,W.jsx)(X,{title:`Identity providers`,op:`identity.idps.list`,description:`Configured external authorities.`}),(0,W.jsx)($,{}),(0,W.jsx)(Qe,{}),(0,W.jsx)(rt,{})]}),(0,W.jsx)(k,{value:`sessions`,children:(0,W.jsx)(Z,{kind:`sessions`})}),(0,W.jsx)(k,{value:`api-keys`,children:(0,W.jsx)(Z,{kind:`api-keys`})}),(0,W.jsx)(k,{value:`audit`,children:(0,W.jsx)(it,{})}),(0,W.jsxs)(k,{value:`security-mode`,className:`space-y-4`,children:[(0,W.jsx)(tt,{}),(0,W.jsx)(nt,{})]}),(0,W.jsx)(k,{value:`policy`,children:(0,W.jsx)(Ke,{})}),(0,W.jsx)(k,{value:`tenants`,children:(0,W.jsx)(xe,{})}),(0,W.jsx)(k,{value:`shards`,children:(0,W.jsx)(ke,{})}),(0,W.jsx)(k,{value:`backup`,children:(0,W.jsx)(Re,{})})]})]})}export{at as default};