@solidxai/core-ui 0.1.20-beta.0 → 0.1.20-beta.1

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 (252) hide show
  1. package/dist/components/common/Link.d.ts.map +1 -1
  2. package/dist/components/common/Link.js +2 -1
  3. package/dist/components/common/Link.js.map +1 -1
  4. package/dist/components/common/Link.tsx +2 -1
  5. package/dist/components/common/SolidSettings/LlmSettings/AiModelConfigTab.d.ts +1 -0
  6. package/dist/components/common/SolidSettings/LlmSettings/AiModelConfigTab.d.ts.map +1 -1
  7. package/dist/components/common/SolidSettings/LlmSettings/AiModelConfigTab.js +109 -23
  8. package/dist/components/common/SolidSettings/LlmSettings/AiModelConfigTab.js.map +1 -1
  9. package/dist/components/common/SolidSettings/LlmSettings/AiModelConfigTab.tsx +155 -34
  10. package/dist/components/core/chatter/SolidChatter.js +2 -2
  11. package/dist/components/core/chatter/SolidChatter.js.map +1 -1
  12. package/dist/components/core/chatter/SolidChatter.tsx +2 -2
  13. package/dist/components/core/common/SolidGenericImport/SolidImportTransaction.js +20 -19
  14. package/dist/components/core/common/SolidGenericImport/SolidImportTransaction.js.map +1 -1
  15. package/dist/components/core/common/SolidGenericImport/SolidImportTransaction.tsx +16 -16
  16. package/dist/components/core/extension/solid-core/moduleMetadata/list/ExportModulePackageRowAction.d.ts.map +1 -1
  17. package/dist/components/core/extension/solid-core/moduleMetadata/list/ExportModulePackageRowAction.js +36 -9
  18. package/dist/components/core/extension/solid-core/moduleMetadata/list/ExportModulePackageRowAction.js.map +1 -1
  19. package/dist/components/core/extension/solid-core/moduleMetadata/list/ExportModulePackageRowAction.tsx +78 -7
  20. package/dist/components/core/extension/solid-core/moduleMetadata/list/ModuleImportListHeaderAction.d.ts +1 -0
  21. package/dist/components/core/extension/solid-core/moduleMetadata/list/ModuleImportListHeaderAction.d.ts.map +1 -1
  22. package/dist/components/core/extension/solid-core/moduleMetadata/list/ModuleImportListHeaderAction.js +1 -1
  23. package/dist/components/core/extension/solid-core/moduleMetadata/list/ModuleImportListHeaderAction.js.map +1 -1
  24. package/dist/components/core/extension/solid-core/moduleMetadata/list/ModuleImportListHeaderAction.tsx +1 -1
  25. package/dist/components/core/extension/solid-core/moduleMetadata/list/RestoreModulePackageRowAction.d.ts +4 -0
  26. package/dist/components/core/extension/solid-core/moduleMetadata/list/RestoreModulePackageRowAction.d.ts.map +1 -0
  27. package/dist/components/core/extension/solid-core/moduleMetadata/list/RestoreModulePackageRowAction.js +131 -0
  28. package/dist/components/core/extension/solid-core/moduleMetadata/list/RestoreModulePackageRowAction.js.map +1 -0
  29. package/dist/components/core/extension/solid-core/moduleMetadata/list/RestoreModulePackageRowAction.tsx +151 -0
  30. package/dist/components/core/extension/solid-core/moduleMetadata/list/UpdateModulePackageRowAction.d.ts +4 -0
  31. package/dist/components/core/extension/solid-core/moduleMetadata/list/UpdateModulePackageRowAction.d.ts.map +1 -0
  32. package/dist/components/core/extension/solid-core/moduleMetadata/list/UpdateModulePackageRowAction.js +13 -0
  33. package/dist/components/core/extension/solid-core/moduleMetadata/list/UpdateModulePackageRowAction.js.map +1 -0
  34. package/dist/components/core/extension/solid-core/moduleMetadata/list/UpdateModulePackageRowAction.tsx +20 -0
  35. package/dist/components/core/form/SolidFormView.d.ts.map +1 -1
  36. package/dist/components/core/form/SolidFormView.js +4 -0
  37. package/dist/components/core/form/SolidFormView.js.map +1 -1
  38. package/dist/components/core/form/SolidFormView.tsx +4 -0
  39. package/dist/components/core/kanban/SolidKanbanView.d.ts.map +1 -1
  40. package/dist/components/core/kanban/SolidKanbanView.js +50 -15
  41. package/dist/components/core/kanban/SolidKanbanView.js.map +1 -1
  42. package/dist/components/core/kanban/SolidKanbanView.tsx +22 -3
  43. package/dist/components/core/list/SolidListView.d.ts.map +1 -1
  44. package/dist/components/core/list/SolidListView.js +16 -3
  45. package/dist/components/core/list/SolidListView.js.map +1 -1
  46. package/dist/components/core/list/SolidListView.tsx +16 -2
  47. package/dist/components/core/list/columns/SolidMediaMultipleColumn.d.ts.map +1 -1
  48. package/dist/components/core/list/columns/SolidMediaMultipleColumn.js +4 -1
  49. package/dist/components/core/list/columns/SolidMediaMultipleColumn.js.map +1 -1
  50. package/dist/components/core/list/columns/SolidMediaMultipleColumn.tsx +4 -1
  51. package/dist/components/core/module/ModulePackageDialog.css +102 -0
  52. package/dist/components/core/module/ModulePackageDialog.d.ts +2 -1
  53. package/dist/components/core/module/ModulePackageDialog.d.ts.map +1 -1
  54. package/dist/components/core/module/ModulePackageDialog.js +216 -68
  55. package/dist/components/core/module/ModulePackageDialog.js.map +1 -1
  56. package/dist/components/core/module/ModulePackageDialog.tsx +356 -76
  57. package/dist/components/core/solid-agent/SolidAgentChat.d.ts.map +1 -1
  58. package/dist/components/core/solid-agent/SolidAgentChat.js +9 -3
  59. package/dist/components/core/solid-agent/SolidAgentChat.js.map +1 -1
  60. package/dist/components/core/solid-agent/SolidAgentChat.tsx +9 -4
  61. package/dist/components/core/solid-agent/SolidAgentMarkdown.d.ts.map +1 -1
  62. package/dist/components/core/solid-agent/SolidAgentMarkdown.js +25 -6
  63. package/dist/components/core/solid-agent/SolidAgentMarkdown.js.map +1 -1
  64. package/dist/components/core/solid-agent/SolidAgentMarkdown.tsx +15 -1
  65. package/dist/components/core/solid-agent/client/agentRuntime.d.ts +5 -0
  66. package/dist/components/core/solid-agent/client/agentRuntime.d.ts.map +1 -1
  67. package/dist/components/core/solid-agent/client/agentRuntime.js +77 -20
  68. package/dist/components/core/solid-agent/client/agentRuntime.js.map +1 -1
  69. package/dist/components/core/solid-agent/client/agentRuntime.ts +29 -1
  70. package/dist/components/core/solid-agent/client/agentSocket.d.ts +5 -1
  71. package/dist/components/core/solid-agent/client/agentSocket.d.ts.map +1 -1
  72. package/dist/components/core/solid-agent/client/agentSocket.js +27 -4
  73. package/dist/components/core/solid-agent/client/agentSocket.js.map +1 -1
  74. package/dist/components/core/solid-agent/client/agentSocket.ts +14 -3
  75. package/dist/components/core/solid-agent/embed/AgentEmbeddingPanel.js +2 -2
  76. package/dist/components/core/solid-agent/embed/AgentEmbeddingPanel.js.map +1 -1
  77. package/dist/components/core/solid-agent/embed/AgentEmbeddingPanel.tsx +5 -5
  78. package/dist/components/core/solid-agent/embed/agentEmbedProtocol.d.ts +2 -0
  79. package/dist/components/core/solid-agent/embed/agentEmbedProtocol.d.ts.map +1 -1
  80. package/dist/components/core/solid-agent/embed/agentEmbedProtocol.js +2 -2
  81. package/dist/components/core/solid-agent/embed/agentEmbedProtocol.js.map +1 -1
  82. package/dist/components/core/solid-agent/embed/agentEmbedProtocol.ts +4 -4
  83. package/dist/components/core/solid-agent/thread/AgentThread.d.ts.map +1 -1
  84. package/dist/components/core/solid-agent/thread/AgentThread.js +61 -26
  85. package/dist/components/core/solid-agent/thread/AgentThread.js.map +1 -1
  86. package/dist/components/core/solid-agent/thread/AgentThread.tsx +74 -40
  87. package/dist/components/core/solid-agent/thread/SolidAgentChatItem.d.ts +2 -1
  88. package/dist/components/core/solid-agent/thread/SolidAgentChatItem.d.ts.map +1 -1
  89. package/dist/components/core/solid-agent/thread/SolidAgentChatItem.js +2 -1
  90. package/dist/components/core/solid-agent/thread/SolidAgentChatItem.js.map +1 -1
  91. package/dist/components/core/solid-agent/thread/SolidAgentChatItem.tsx +3 -1
  92. package/dist/components/core/solid-agent/types.d.ts +3 -0
  93. package/dist/components/core/solid-agent/types.d.ts.map +1 -1
  94. package/dist/components/core/solid-agent/types.js +0 -9
  95. package/dist/components/core/solid-agent/types.js.map +1 -1
  96. package/dist/components/core/solid-agent/types.ts +4 -2
  97. package/dist/components/core/solid-agent/widgets/DefaultAssistantMessageChatWidget.d.ts +1 -1
  98. package/dist/components/core/solid-agent/widgets/DefaultAssistantMessageChatWidget.d.ts.map +1 -1
  99. package/dist/components/core/solid-agent/widgets/DefaultAssistantMessageChatWidget.js +5 -2
  100. package/dist/components/core/solid-agent/widgets/DefaultAssistantMessageChatWidget.js.map +1 -1
  101. package/dist/components/core/solid-agent/widgets/DefaultAssistantMessageChatWidget.tsx +11 -5
  102. package/dist/components/core/solid-agent/widgets/DefaultErrorChatWidget.js +3 -0
  103. package/dist/components/core/solid-agent/widgets/DefaultErrorChatWidget.js.map +1 -1
  104. package/dist/components/core/solid-agent/widgets/DefaultErrorChatWidget.tsx +4 -0
  105. package/dist/components/core/solid-agent/widgets/DefaultNoticeChatWidget.js +3 -0
  106. package/dist/components/core/solid-agent/widgets/DefaultNoticeChatWidget.js.map +1 -1
  107. package/dist/components/core/solid-agent/widgets/DefaultNoticeChatWidget.tsx +4 -0
  108. package/dist/components/core/solid-agent/widgets/DefaultThinkingChatWidget.js +3 -0
  109. package/dist/components/core/solid-agent/widgets/DefaultThinkingChatWidget.js.map +1 -1
  110. package/dist/components/core/solid-agent/widgets/DefaultThinkingChatWidget.tsx +4 -0
  111. package/dist/components/core/solid-agent/widgets/DefaultToolCallChatWidget.js +3 -0
  112. package/dist/components/core/solid-agent/widgets/DefaultToolCallChatWidget.js.map +1 -1
  113. package/dist/components/core/solid-agent/widgets/DefaultToolCallChatWidget.tsx +4 -0
  114. package/dist/components/core/solid-agent/widgets/DefaultUnknownChatWidget.js +3 -0
  115. package/dist/components/core/solid-agent/widgets/DefaultUnknownChatWidget.js.map +1 -1
  116. package/dist/components/core/solid-agent/widgets/DefaultUnknownChatWidget.tsx +4 -0
  117. package/dist/components/core/solid-agent/widgets/DefaultUserMessageChatWidget.js +3 -0
  118. package/dist/components/core/solid-agent/widgets/DefaultUserMessageChatWidget.js.map +1 -1
  119. package/dist/components/core/solid-agent/widgets/DefaultUserMessageChatWidget.tsx +4 -0
  120. package/dist/components/core/solid-agent/widgets/SolidChecklistChatWidget.js +3 -0
  121. package/dist/components/core/solid-agent/widgets/SolidChecklistChatWidget.js.map +1 -1
  122. package/dist/components/core/solid-agent/widgets/SolidChecklistChatWidget.tsx +4 -0
  123. package/dist/components/core/solid-agent/widgets/SolidCodeChatWidget.js +3 -0
  124. package/dist/components/core/solid-agent/widgets/SolidCodeChatWidget.js.map +1 -1
  125. package/dist/components/core/solid-agent/widgets/SolidCodeChatWidget.tsx +4 -0
  126. package/dist/components/core/solid-agent/widgets/SolidDiffListChatWidget.js +3 -0
  127. package/dist/components/core/solid-agent/widgets/SolidDiffListChatWidget.js.map +1 -1
  128. package/dist/components/core/solid-agent/widgets/SolidDiffListChatWidget.tsx +4 -0
  129. package/dist/components/core/solid-agent/widgets/SolidGalleryChatWidget.js +19 -0
  130. package/dist/components/core/solid-agent/widgets/SolidGalleryChatWidget.js.map +1 -1
  131. package/dist/components/core/solid-agent/widgets/SolidGalleryChatWidget.tsx +20 -0
  132. package/dist/components/core/solid-agent/widgets/SolidJsonChatWidget.js +3 -0
  133. package/dist/components/core/solid-agent/widgets/SolidJsonChatWidget.js.map +1 -1
  134. package/dist/components/core/solid-agent/widgets/SolidJsonChatWidget.tsx +4 -0
  135. package/dist/components/core/solid-agent/widgets/SolidLinkCardChatWidget.js +3 -0
  136. package/dist/components/core/solid-agent/widgets/SolidLinkCardChatWidget.js.map +1 -1
  137. package/dist/components/core/solid-agent/widgets/SolidLinkCardChatWidget.tsx +4 -0
  138. package/dist/components/core/solid-agent/widgets/SolidMarkdownChatWidget.js +3 -0
  139. package/dist/components/core/solid-agent/widgets/SolidMarkdownChatWidget.js.map +1 -1
  140. package/dist/components/core/solid-agent/widgets/SolidMarkdownChatWidget.tsx +4 -0
  141. package/dist/components/core/solid-agent/widgets/SolidProgressChatWidget.js +3 -0
  142. package/dist/components/core/solid-agent/widgets/SolidProgressChatWidget.js.map +1 -1
  143. package/dist/components/core/solid-agent/widgets/SolidProgressChatWidget.tsx +4 -0
  144. package/dist/components/core/solid-agent/widgets/SolidQuestionChatWidget.js +3 -0
  145. package/dist/components/core/solid-agent/widgets/SolidQuestionChatWidget.js.map +1 -1
  146. package/dist/components/core/solid-agent/widgets/SolidQuestionChatWidget.tsx +4 -0
  147. package/dist/components/core/solid-agent/widgets/SolidStatusChatWidget.js +3 -0
  148. package/dist/components/core/solid-agent/widgets/SolidStatusChatWidget.js.map +1 -1
  149. package/dist/components/core/solid-agent/widgets/SolidStatusChatWidget.tsx +4 -0
  150. package/dist/components/core/solid-agent/widgets/SolidTableChatWidget.js +3 -0
  151. package/dist/components/core/solid-agent/widgets/SolidTableChatWidget.js.map +1 -1
  152. package/dist/components/core/solid-agent/widgets/SolidTableChatWidget.tsx +4 -0
  153. package/dist/components/core/solid-agent/widgets/SolidToolActivityChatWidget.js +3 -0
  154. package/dist/components/core/solid-agent/widgets/SolidToolActivityChatWidget.js.map +1 -1
  155. package/dist/components/core/solid-agent/widgets/SolidToolActivityChatWidget.tsx +4 -0
  156. package/dist/components/core/solid-agent/widgets/solidChatWidgets.module.css +9 -1
  157. package/dist/components/core/users/CreateUser.d.ts.map +1 -1
  158. package/dist/components/core/users/CreateUser.js +23 -8
  159. package/dist/components/core/users/CreateUser.js.map +1 -1
  160. package/dist/components/core/users/CreateUser.tsx +10 -6
  161. package/dist/components/layout/AdminTopHeader.js +2 -2
  162. package/dist/components/layout/AdminTopHeader.js.map +1 -1
  163. package/dist/components/layout/AdminTopHeader.tsx +2 -2
  164. package/dist/components/layout/AppSidebar.d.ts.map +1 -1
  165. package/dist/components/layout/AppSidebar.js +21 -5
  166. package/dist/components/layout/AppSidebar.js.map +1 -1
  167. package/dist/components/layout/AppSidebar.tsx +24 -6
  168. package/dist/components/layout/SolidAiStudioLayout.d.ts.map +1 -1
  169. package/dist/components/layout/SolidAiStudioLayout.js +3 -4
  170. package/dist/components/layout/SolidAiStudioLayout.js.map +1 -1
  171. package/dist/components/layout/SolidAiStudioLayout.tsx +3 -4
  172. package/dist/components/layout/user-profile-menu.js +10 -10
  173. package/dist/components/layout/user-profile-menu.js.map +1 -1
  174. package/dist/components/layout/user-profile-menu.tsx +3 -3
  175. package/dist/components/shad-cn-ui/SolidLightbox.d.ts +2 -1
  176. package/dist/components/shad-cn-ui/SolidLightbox.d.ts.map +1 -1
  177. package/dist/components/shad-cn-ui/SolidLightbox.js +11 -4
  178. package/dist/components/shad-cn-ui/SolidLightbox.js.map +1 -1
  179. package/dist/components/shad-cn-ui/SolidLightbox.tsx +14 -1
  180. package/dist/helpers/modelViewPersistence.d.ts +2 -0
  181. package/dist/helpers/modelViewPersistence.d.ts.map +1 -1
  182. package/dist/helpers/modelViewPersistence.js +72 -0
  183. package/dist/helpers/modelViewPersistence.js.map +1 -1
  184. package/dist/helpers/modelViewPersistence.ts +79 -0
  185. package/dist/helpers/registry.d.ts +6 -2
  186. package/dist/helpers/registry.d.ts.map +1 -1
  187. package/dist/helpers/registry.js +68 -3
  188. package/dist/helpers/registry.js.map +1 -1
  189. package/dist/helpers/registry.ts +62 -4
  190. package/dist/hooks/useModelsDevModels.d.ts +43 -0
  191. package/dist/hooks/useModelsDevModels.d.ts.map +1 -0
  192. package/dist/hooks/useModelsDevModels.js +81 -0
  193. package/dist/hooks/useModelsDevModels.js.map +1 -0
  194. package/dist/hooks/useModelsDevModels.ts +106 -0
  195. package/dist/hooks/useRouter.d.ts.map +1 -1
  196. package/dist/hooks/useRouter.js +3 -2
  197. package/dist/hooks/useRouter.js.map +1 -1
  198. package/dist/hooks/useRouter.ts +3 -2
  199. package/dist/index.d.ts +2 -2
  200. package/dist/index.d.ts.map +1 -1
  201. package/dist/index.js +1 -1
  202. package/dist/index.js.map +1 -1
  203. package/dist/index.ts +4 -1
  204. package/dist/modules/solidUiModule.d.ts +3 -2
  205. package/dist/modules/solidUiModule.d.ts.map +1 -1
  206. package/dist/modules/solidUiModule.js +1 -1
  207. package/dist/modules/solidUiModule.js.map +1 -1
  208. package/dist/modules/solidUiModule.ts +5 -1
  209. package/dist/redux/api/moduleApi.d.ts +12 -2
  210. package/dist/redux/api/moduleApi.d.ts.map +1 -1
  211. package/dist/redux/api/moduleApi.js +33 -3
  212. package/dist/redux/api/moduleApi.js.map +1 -1
  213. package/dist/redux/api/moduleApi.ts +17 -2
  214. package/dist/redux/api/solidChatterMessageApi.d.ts +3 -1
  215. package/dist/redux/api/solidChatterMessageApi.d.ts.map +1 -1
  216. package/dist/redux/api/solidChatterMessageApi.js +9 -1
  217. package/dist/redux/api/solidChatterMessageApi.js.map +1 -1
  218. package/dist/redux/api/solidChatterMessageApi.ts +9 -1
  219. package/dist/redux/store/defaultStoreConfig.d.ts +9 -1
  220. package/dist/redux/store/defaultStoreConfig.d.ts.map +1 -1
  221. package/dist/resources/globals.css +30 -0
  222. package/dist/resources/solid-custom.css +10 -6
  223. package/dist/resources/solid-tailwind-generated.css +1 -1
  224. package/dist/routes/AppEventListener.js +1 -1
  225. package/dist/routes/AppEventListener.js.map +1 -1
  226. package/dist/routes/AppEventListener.tsx +1 -1
  227. package/dist/routes/pages/admin/core/AgentPersonaHistory.css +130 -0
  228. package/dist/routes/pages/admin/core/AgentPersonaHistory.d.ts +7 -0
  229. package/dist/routes/pages/admin/core/AgentPersonaHistory.d.ts.map +1 -0
  230. package/dist/routes/pages/admin/core/AgentPersonaHistory.js +228 -0
  231. package/dist/routes/pages/admin/core/AgentPersonaHistory.js.map +1 -0
  232. package/dist/routes/pages/admin/core/AgentPersonaHistory.tsx +234 -0
  233. package/dist/routes/pages/admin/core/AgentRegistryEditorPage.css +6 -14
  234. package/dist/routes/pages/admin/core/AgentRegistryEditorPage.d.ts.map +1 -1
  235. package/dist/routes/pages/admin/core/AgentRegistryEditorPage.js +186 -146
  236. package/dist/routes/pages/admin/core/AgentRegistryEditorPage.js.map +1 -1
  237. package/dist/routes/pages/admin/core/AgentRegistryEditorPage.tsx +170 -118
  238. package/dist/routes/pages/admin/core/ArchivedChatterMessagesPage.d.ts +2 -0
  239. package/dist/routes/pages/admin/core/ArchivedChatterMessagesPage.d.ts.map +1 -0
  240. package/dist/routes/pages/admin/core/ArchivedChatterMessagesPage.js +108 -0
  241. package/dist/routes/pages/admin/core/ArchivedChatterMessagesPage.js.map +1 -0
  242. package/dist/routes/pages/admin/core/ArchivedChatterMessagesPage.tsx +96 -0
  243. package/dist/routes/solidRoutes.d.ts.map +1 -1
  244. package/dist/routes/solidRoutes.js +2 -0
  245. package/dist/routes/solidRoutes.js.map +1 -1
  246. package/dist/routes/solidRoutes.tsx +2 -0
  247. package/dist/types/extension-registry.d.ts +12 -0
  248. package/dist/types/extension-registry.d.ts.map +1 -1
  249. package/dist/types/extension-registry.js.map +1 -1
  250. package/dist/types/extension-registry.ts +15 -0
  251. package/dist/types/solid-core.d.ts +2 -0
  252. package/package.json +2 -1
@@ -1,6 +1,5 @@
1
1
  import React from "react";
2
- import { createPortal } from "react-dom";
3
- import { ArrowLeft, ChevronDown, Ellipsis, ExternalLink, Eye, FlaskConical, Pencil, Plus, RefreshCw, Trash2 } from "lucide-react";
2
+ import { ArrowLeft, Ellipsis, ExternalLink, Eye, FlaskConical, Pencil, Plus, RefreshCw, Trash2 } from "lucide-react";
4
3
  import { useDispatch } from "react-redux";
5
4
  import { useNavigate, useParams } from "react-router-dom";
6
5
  import { createSolidEntityApi } from "../../../../redux/api/solidEntityApi";
@@ -8,14 +7,15 @@ import { useGetSolidSettingsQuery } from "../../../../redux/api/solidSettingsApi
8
7
  import { getSettingsMap } from "../../../../helpers/settingsPayload";
9
8
  import { showToast } from "../../../../redux/features/toastSlice";
10
9
  import { AgentRegistryAuditPanel } from "./AgentRegistryAuditPanel";
10
+ import { AgentPersonaHistory } from "./AgentPersonaHistory";
11
11
  import { AgentHubTagsField, agentHubTagsFrom, agentHubTagsPayload, type AgentHubTag } from "./AgentHubTagsField";
12
12
  import { AgentResourceCardWidget } from "../../../../components/core/extension/solid-core/agentRegistry/card/AgentResourceCardWidget";
13
13
  import { AgentSessionsPanel } from "../../../../components/core/extension/solid-core/agentToolRegistry/AgentToolSessionsPanel";
14
14
  import { AgentProcessesPanel } from "../../../../components/core/extension/solid-core/agentToolRegistry/AgentProcessesPanel";
15
15
  import type { SolidKanbanCardWidgetProps } from "../../../../types/solid-core";
16
16
  import { SolidWorkflowStatusPill } from "../../../../components/core/form/SolidDraftPublishWorkflow";
17
- import { ALLOWED_MODELS_BY_PROVIDER, type AllowedModelProvider } from "../../../../constants/allowed-ai-models";
18
- import { SolidButton, SolidCodeEditor, SolidDialog, SolidDialogBody, SolidDropdownMenu, SolidDropdownMenuContent, SolidDropdownMenuItem, SolidDropdownMenuTrigger, SolidIconPicker, SolidInput, SolidTabGroup } from "../../../../components/shad-cn-ui";
17
+ import { getModelsDevModels, useModelsDevCatalog } from "../../../../hooks/useModelsDevModels";
18
+ import { SolidAutocomplete, SolidButton, SolidCodeEditor, SolidDialog, SolidDialogBody, SolidDropdownMenu, SolidDropdownMenuContent, SolidDropdownMenuItem, SolidDropdownMenuTrigger, SolidIconPicker, SolidInput, SolidTabGroup } from "../../../../components/shad-cn-ui";
19
19
  import { SolidAgentEmbedded } from "../../../../components/core/solid-agent/SolidAgentEmbedded";
20
20
  import { SolidAgentMarkdown } from "../../../../components/core/solid-agent/SolidAgentMarkdown";
21
21
  import { AgentEmbeddingPanel } from "../../../../components/core/solid-agent/embed/AgentEmbeddingPanel";
@@ -23,7 +23,7 @@ import "./AgentRegistryEditorPage.css";
23
23
 
24
24
  type Item = { id: number; name?: string; title?: string; displayName?: string; description?: string; iconName?: string; key?: string; module?: { id?: number; displayName?: string }; [key: string]: any };
25
25
  type Link = { id: number; agentSkillRegistry?: Item; agentToolRegistry?: Item; roleMetadata?: Item; secret?: Item; envVarName?: string; alwaysInclude?: boolean; requiresApproval?: boolean };
26
- type Input = { name: string; description: string; dataType: string };
26
+ type Input = { name: string; description: string; dataType: string; defaultValue?: unknown; optional: boolean };
27
27
  type Agent = Item & {
28
28
  configVersion?: number;
29
29
  systemPrompt?: string; requiredInputs?: string; reasoningModelKey?: string; fastModelKey?: string; status?: string;
@@ -31,110 +31,113 @@ type Agent = Item & {
31
31
  agentSkills?: Link[]; agentTools?: Link[]; agentRoles?: Link[]; agentSecrets?: Link[];
32
32
  tags?: AgentHubTag[];
33
33
  };
34
- type ProviderModelOption = { provider: AllowedModelProvider; model: string; value: string };
34
+ type ProviderModelOption = { provider: string; providerLabel: string; model: string; value: string; note?: string };
35
35
 
36
- const PROVIDER_LABELS: Record<AllowedModelProvider, string> = {
36
+ const PROVIDER_LABELS: Record<string, string> = {
37
37
  anthropic: "Anthropic",
38
38
  openai: "OpenAI",
39
39
  openrouter: "OpenRouter",
40
40
  };
41
+ const BUILT_IN_PROVIDER_TYPES = ["openai", "anthropic"];
41
42
 
42
- function ModelPicker({ value, options, placeholder, onChange }: {
43
+ type AiProviderConfig = { type?: string; apiKey?: unknown; region?: string };
44
+ type AiModelConfig = { providerId?: string; model?: string };
45
+
46
+ /**
47
+ * Build picker options from the AI settings: every provider with an API key, its models from
48
+ * models.dev, plus the models chosen in settings and any already-saved values for this agent.
49
+ */
50
+ function buildModelOptions(
51
+ providers: Record<string, AiProviderConfig>,
52
+ settingsModels: Record<string, AiModelConfig | undefined>,
53
+ catalog: Parameters<typeof getModelsDevModels>[0],
54
+ savedValues: string[],
55
+ ): ProviderModelOption[] {
56
+ const enabled = Object.entries(providers)
57
+ .filter(([, entry]) => typeof entry?.apiKey === "string" && entry.apiKey.trim().length > 0);
58
+ const options: ProviderModelOption[] = [];
59
+ const seen = new Set<string>();
60
+ const add = (provider: string, model: string, note?: string) => {
61
+ const value = `${provider}:${model}`;
62
+ if (!model || seen.has(value)) return;
63
+ seen.add(value);
64
+ options.push({ provider, providerLabel: PROVIDER_LABELS[provider] ?? provider, model, value, note });
65
+ };
66
+ for (const [provider, entry] of enabled) {
67
+ for (const [role, config] of Object.entries(settingsModels)) {
68
+ if (config?.providerId === provider && config.model) add(provider, config.model, `${role} model in AI settings`);
69
+ }
70
+ for (const value of savedValues) {
71
+ if (value.startsWith(`${provider}:`)) add(provider, value.slice(provider.length + 1), "currently saved");
72
+ }
73
+ const type = entry.type && BUILT_IN_PROVIDER_TYPES.includes(entry.type) ? entry.type : undefined;
74
+ for (const model of getModelsDevModels(catalog, [provider, type])) add(provider, model.id);
75
+ }
76
+ return options;
77
+ }
78
+
79
+ const OTHER_MODEL = "__other_model__";
80
+
81
+ function SearchableSelect({ value, options, placeholder, disabled, onChange }: {
43
82
  value: string;
44
- options: ProviderModelOption[];
83
+ options: { label: string; value: string }[];
45
84
  placeholder: string;
85
+ disabled?: boolean;
46
86
  onChange: (value: string) => void;
47
87
  }) {
48
- const rootRef = React.useRef<HTMLDivElement>(null);
49
- const menuRef = React.useRef<HTMLDivElement>(null);
50
- const [open, setOpen] = React.useState(false);
51
88
  const [query, setQuery] = React.useState("");
52
- const [activeIndex, setActiveIndex] = React.useState(0);
53
- const [menuStyle, setMenuStyle] = React.useState<React.CSSProperties>({});
54
- const selected = options.find((option) => option.value === value);
55
- const filtered = options.filter((option) =>
56
- `${PROVIDER_LABELS[option.provider]} ${option.model}`.toLowerCase().includes(query.trim().toLowerCase()));
57
- const groups = (Object.keys(ALLOWED_MODELS_BY_PROVIDER) as AllowedModelProvider[])
58
- .map((provider) => ({ provider, options: filtered.filter((option) => option.provider === provider) }))
59
- .filter((group) => group.options.length > 0);
89
+ const selectedLabel = options.find((option) => option.value === value)?.label;
90
+ const selected = React.useMemo(() => selectedLabel ? { label: selectedLabel, value } : null, [selectedLabel, value]);
91
+ const suggestions = options.filter((option) =>
92
+ `${option.label} ${option.value}`.toLowerCase().includes(query.trim().toLowerCase()));
60
93
 
61
- React.useEffect(() => {
62
- if (!open) return;
63
- const positionMenu = () => {
64
- const bounds = rootRef.current?.getBoundingClientRect();
65
- if (!bounds) return;
66
- const gap = 6;
67
- const maxMenuHeight = Math.min(288, window.innerHeight - 24);
68
- const spaceBelow = window.innerHeight - bounds.bottom - gap - 12;
69
- const spaceAbove = bounds.top - gap - 12;
70
- const openAbove = spaceBelow < Math.min(220, maxMenuHeight) && spaceAbove > spaceBelow;
71
- const availableHeight = Math.max(120, Math.min(maxMenuHeight, openAbove ? spaceAbove : spaceBelow));
72
- setMenuStyle({
73
- position: "fixed",
74
- left: bounds.left,
75
- width: bounds.width,
76
- maxHeight: availableHeight,
77
- ...(openAbove
78
- ? { bottom: window.innerHeight - bounds.top + gap }
79
- : { top: bounds.bottom + gap }),
80
- });
81
- };
82
- positionMenu();
83
- window.addEventListener("resize", positionMenu);
84
- window.addEventListener("scroll", positionMenu, true);
85
- const handleOutsideClick = (event: MouseEvent) => {
86
- const target = event.target as Node;
87
- if (!rootRef.current?.contains(target) && !menuRef.current?.contains(target)) setOpen(false);
88
- };
89
- document.addEventListener("mousedown", handleOutsideClick);
90
- return () => {
91
- window.removeEventListener("resize", positionMenu);
92
- window.removeEventListener("scroll", positionMenu, true);
93
- document.removeEventListener("mousedown", handleOutsideClick);
94
- };
95
- }, [open]);
94
+ return <SolidAutocomplete
95
+ className="solid-standard-autocomplete w-full"
96
+ value={selected}
97
+ suggestions={suggestions}
98
+ completeMethod={({ query: next }) => setQuery(next)}
99
+ onChange={(event) => onChange(event.value?.value ?? "")}
100
+ field="label"
101
+ placeholder={placeholder}
102
+ disabled={disabled}
103
+ dropdown
104
+ forceSelection
105
+ portal
106
+ />;
107
+ }
96
108
 
97
- const choose = (option: ProviderModelOption) => {
98
- onChange(option.value);
99
- setQuery("");
100
- setOpen(false);
101
- };
102
- let flatIndex = -1;
103
-
104
- return <div className="agent-editor__model-picker" ref={rootRef}>
105
- <div className="agent-editor__model-control">
106
- <input
107
- role="combobox"
108
- aria-expanded={open}
109
- aria-autocomplete="list"
110
- aria-label={placeholder}
111
- placeholder={selected ? `${PROVIDER_LABELS[selected.provider]} / ${selected.model}` : value || placeholder}
112
- value={open ? query : ""}
113
- onFocus={() => { setQuery(""); setActiveIndex(0); setOpen(true); }}
114
- onChange={(event) => { setQuery(event.target.value); setActiveIndex(0); setOpen(true); }}
115
- onKeyDown={(event) => {
116
- if (event.key === "Escape") { setOpen(false); setQuery(""); }
117
- if (event.key === "ArrowDown") { event.preventDefault(); setOpen(true); setActiveIndex((index) => Math.min(index + 1, filtered.length - 1)); }
118
- if (event.key === "ArrowUp") { event.preventDefault(); setActiveIndex((index) => Math.max(index - 1, 0)); }
119
- if (event.key === "Enter" && open && filtered[activeIndex]) { event.preventDefault(); choose(filtered[activeIndex]); }
120
- }}
121
- />
122
- <button type="button" aria-label={open ? "Close model options" : "Show model options"} onMouseDown={(event) => event.preventDefault()} onClick={() => { setOpen((current) => !current); setQuery(""); }}><ChevronDown size={16} /></button>
109
+ function ModelPicker({ value, options, providers, providerConfig, onChange }: {
110
+ value: string;
111
+ options: ProviderModelOption[];
112
+ providers: { label: string; value: string }[];
113
+ providerConfig: Record<string, AiProviderConfig>;
114
+ onChange: (value: string) => void;
115
+ }) {
116
+ const separator = value.indexOf(":");
117
+ const provider = separator < 0 ? "" : value.slice(0, separator);
118
+ const model = separator < 0 ? "" : value.slice(separator + 1);
119
+ const availableModels = options.filter((option) => option.provider === provider);
120
+ const [otherSelected, setOtherSelected] = React.useState(false);
121
+ const showOther = !!provider && (otherSelected || (!!model && !availableModels.some((option) => option.model === model)));
122
+
123
+ return <div className="agent-editor__stack">
124
+ <div className="agent-editor__field"><span>Provider *</span>
125
+ <SearchableSelect value={provider} options={providers} placeholder="Select provider"
126
+ onChange={(next) => { setOtherSelected(false); onChange(`${next}:`); }} />
127
+ {providerConfig[provider]?.type === "bedrock" && providerConfig[provider]?.region &&
128
+ <small><em>Region: {providerConfig[provider].region}</em></small>}
129
+ </div>
130
+ <div className="agent-editor__field"><span>Model *</span>
131
+ <SearchableSelect value={showOther ? OTHER_MODEL : model}
132
+ options={[...availableModels.map((option) => ({ label: option.model, value: option.model })), { label: "Other", value: OTHER_MODEL }]}
133
+ placeholder="Select model" disabled={!provider}
134
+ onChange={(next) => {
135
+ setOtherSelected(next === OTHER_MODEL);
136
+ onChange(`${provider}:${next === OTHER_MODEL ? "" : next}`);
137
+ }} />
138
+ {showOther && <SolidInput className="w-full" aria-label="Custom model ID" placeholder="Enter model ID" value={model}
139
+ onChange={(event) => onChange(`${provider}:${event.target.value}`)} />}
123
140
  </div>
124
- {open && createPortal(<div ref={menuRef} className="agent-editor__model-menu" style={menuStyle} role="listbox">
125
- {!groups.length ? <div className="agent-editor__model-empty">{options.length ? "No matching models." : "No enabled providers. Add an API key in AI Settings."}</div>
126
- : groups.map((group) => <section className="agent-editor__model-group" key={group.provider}>
127
- <h3>{PROVIDER_LABELS[group.provider]}</h3>
128
- {group.options.map((option) => {
129
- flatIndex += 1;
130
- const index = flatIndex;
131
- return <button type="button" role="option" aria-selected={option.value === value} className={`agent-editor__model-option${index === activeIndex ? " is-active" : ""}`}
132
- key={option.value} onMouseDown={(event) => event.preventDefault()} onMouseEnter={() => setActiveIndex(index)} onClick={() => choose(option)}>
133
- <span>{option.model}</span><small>{option.provider}:{option.model}</small>
134
- </button>;
135
- })}
136
- </section>)}
137
- </div>, document.body)}
138
141
  </div>;
139
142
  }
140
143
 
@@ -217,17 +220,41 @@ function parseInputs(value: unknown): Input[] {
217
220
  const parsed = typeof value === "string" ? JSON.parse(value) : value;
218
221
  if (Array.isArray(parsed)) return parsed.map((input) => ({
219
222
  name: String(input.name ?? input.variableName ?? ""), description: String(input.description ?? ""),
220
- dataType: String(input.dataType ?? input.type ?? "string"),
223
+ dataType: String(input.dataType ?? input.type ?? "string"), defaultValue: input.defaultValue ?? null,
224
+ optional: input.optional === true,
221
225
  }));
222
226
  // Existing agent definitions may use a name-keyed object.
223
227
  if (parsed && typeof parsed === "object") return Object.entries(parsed).map(([name, definition]: [string, any]) => ({
224
228
  name, description: String(definition?.description ?? ""),
225
- dataType: String(definition?.dataType ?? definition?.type ?? "string"),
229
+ dataType: String(definition?.dataType ?? definition?.type ?? "string"), defaultValue: definition?.defaultValue ?? null,
230
+ optional: definition?.optional === true,
226
231
  }));
227
232
  } catch { /* Keep malformed historical values from crashing the editor. */ }
228
233
  return [];
229
234
  }
230
235
 
236
+ function parseDefaultValue(raw: string, dataType: string): unknown {
237
+ if (dataType === "string" || dataType === "date" || dataType === "datetime") return raw;
238
+ if (dataType === "boolean") {
239
+ if (raw !== "true" && raw !== "false") throw new Error(`Default value must be true or false for ${dataType}.`);
240
+ return raw === "true";
241
+ }
242
+ if (dataType === "number" || dataType === "integer") {
243
+ const value = Number(raw);
244
+ if (!Number.isFinite(value) || (dataType === "integer" && !Number.isSafeInteger(value))) throw new Error(`Default value must be a valid ${dataType}.`);
245
+ return value;
246
+ }
247
+ const value = JSON.parse(raw);
248
+ if (dataType === "array" && !Array.isArray(value)) throw new Error("Default value must be a JSON array.");
249
+ if (dataType === "object" && (!value || typeof value !== "object" || Array.isArray(value))) throw new Error("Default value must be a JSON object.");
250
+ return value;
251
+ }
252
+
253
+ function formatDefaultValue(value: unknown): string {
254
+ if (value == null) return "";
255
+ return typeof value === "string" ? value : JSON.stringify(value);
256
+ }
257
+
231
258
  function apiError(error: any): string {
232
259
  const value = error?.data?.data?.message ?? error?.data?.message ?? error?.message;
233
260
  return Array.isArray(value) ? value.join("; ") : typeof value === "string" ? value : "The save failed.";
@@ -269,12 +296,16 @@ function LinkPicker({ label, description, options, selected, onAdd, onRemove, cr
269
296
  }) {
270
297
  const [search, setSearch] = React.useState("");
271
298
  const [open, setOpen] = React.useState(false);
299
+ const showAssociatedCount = label === "Skills" || label === "Tools";
272
300
  const available = options.filter((item) => !selected.some((selectedItem) => selectedItem.id === item.id)
273
301
  && `${item.name ?? item.displayName ?? item.key ?? ""} ${item.description ?? ""}`.toLowerCase().includes(search.toLowerCase())).slice(0, 20);
274
302
  return <section className="agent-editor__section">
275
303
  <div className="agent-editor__section-head"><div><h2>{label}</h2><p>{description}</p></div>
276
304
  {createUrl && <a href={createUrl} target="_blank" rel="noopener noreferrer" className="agent-editor__new-link">Create {label === "Skills" ? "skill" : "tool"} <ExternalLink size={14} /></a>}
277
305
  </div>
306
+ {showAssociatedCount && <div className="agent-editor__linked-count" role="status">
307
+ {selected.length} {label.toLowerCase()} associated
308
+ </div>}
278
309
  <div className="agent-editor__picker">
279
310
  <SolidInput value={search} placeholder={`Search and add ${label.toLowerCase()}…`} aria-label={`Search ${label.toLowerCase()}`}
280
311
  onFocus={() => setOpen(true)} onChange={(event) => { setSearch(event.target.value); setOpen(true); }} />
@@ -413,18 +444,26 @@ export function AgentRegistryEditorPage() {
413
444
  }, [skills.refetch, tools.refetch]);
414
445
 
415
446
  const configValue = getSettingsMap(settings).solidXGenAiCodeBuilderConfig;
416
- let enabledProviders: Record<string, { apiKey?: unknown }> = {};
447
+ let aiConfig: { providers?: Record<string, AiProviderConfig>; models?: { default?: AiModelConfig; main?: AiModelConfig; fast?: AiModelConfig } } = {};
417
448
  try {
418
- const config = typeof configValue === "string" ? JSON.parse(configValue) : configValue;
419
- enabledProviders = config?.providers ?? {};
449
+ aiConfig = (typeof configValue === "string" ? JSON.parse(configValue) : configValue) ?? {};
420
450
  } catch { /* Invalid configuration has no enabled providers. */ }
421
- const modelOptions = (Object.keys(ALLOWED_MODELS_BY_PROVIDER) as AllowedModelProvider[])
422
- .filter((provider) => typeof enabledProviders[provider]?.apiKey === "string" && (enabledProviders[provider].apiKey as string).trim().length > 0)
423
- .flatMap((provider) => ALLOWED_MODELS_BY_PROVIDER[provider].map((model) => ({
424
- provider,
425
- model,
426
- value: `${provider}:${model}`,
427
- })));
451
+ const { catalog: modelsCatalog } = useModelsDevCatalog();
452
+ const savedModelKeys = [record?.reasoningModelKey, record?.fastModelKey].filter((key): key is string => !!key);
453
+ const modelOptions = buildModelOptions(
454
+ aiConfig.providers ?? {},
455
+ { Reasoning: aiConfig.models?.default ?? aiConfig.models?.main, Fast: aiConfig.models?.fast },
456
+ modelsCatalog,
457
+ savedModelKeys,
458
+ );
459
+ const providerOptions = Object.entries(aiConfig.providers ?? {})
460
+ .filter(([, entry]) => typeof entry?.apiKey === "string" && entry.apiKey.trim().length > 0)
461
+ .map(([provider]) => ({ label: modelsCatalog?.[provider]?.name ?? PROVIDER_LABELS[provider] ?? provider, value: provider }));
462
+ const isValidModelKey = (value: string) => {
463
+ const separator = value.indexOf(":");
464
+ return separator > 0 && providerOptions.some((provider) => provider.value === value.slice(0, separator)) &&
465
+ !!value.slice(separator + 1).trim();
466
+ };
428
467
  const toggle = (setter: React.Dispatch<React.SetStateAction<number[]>>, value: number) =>
429
468
  setter((current) => current.includes(value) ? current.filter((id) => id !== value) : [...current, value]);
430
469
 
@@ -454,8 +493,8 @@ export function AgentRegistryEditorPage() {
454
493
  if (!name.trim()) next.name = "Name is required.";
455
494
  if (!title.trim()) next.title = "Title is required.";
456
495
  if (!systemPrompt.trim()) next.systemPrompt = "Persona instructions are required.";
457
- if (!modelOptions.some((option) => option.value === reasoningModelKey)) next.reasoningModelKey = "Choose an enabled reasoning provider and model.";
458
- if (!modelOptions.some((option) => option.value === fastModelKey)) next.fastModelKey = "Choose an enabled fast provider and model.";
496
+ if (!isValidModelKey(reasoningModelKey)) next.reasoningModelKey = "Choose an enabled reasoning provider and model.";
497
+ if (!isValidModelKey(fastModelKey)) next.fastModelKey = "Choose an enabled fast provider and model.";
459
498
  if (inputs.some((input) => !input.name.trim() || !input.dataType)) next.inputs = "Each input needs a name and data type.";
460
499
  if (new Set(inputs.map((input) => input.name.trim().toLowerCase())).size !== inputs.length) next.inputs = "Input names must be unique.";
461
500
  if (stepLimit < 1 || turnStepLimit < 1 || costLimit < 0) next.limits = "Step limits must be positive and cost limit cannot be negative.";
@@ -465,9 +504,19 @@ export function AgentRegistryEditorPage() {
465
504
  dispatch(showToast({ severity: "error", summary: "Missing information", detail: Object.values(next).join(" ") }));
466
505
  return;
467
506
  }
507
+ let normalizedInputs: Input[];
508
+ try {
509
+ normalizedInputs = inputs.map((input) => ({ ...input, name: input.name.trim(), description: input.description.trim(),
510
+ defaultValue: input.defaultValue === "" || input.defaultValue == null ? null : parseDefaultValue(String(input.defaultValue), input.dataType) }));
511
+ } catch (error) {
512
+ next.inputs = error instanceof Error ? error.message : "Check the default input values.";
513
+ setErrors(next);
514
+ setTab("basics");
515
+ return;
516
+ }
468
517
  const payload = {
469
518
  name: name.trim(), title: title.trim(), description: description.trim(), iconName,
470
- requiredInputs: JSON.stringify(inputs.map((input) => ({ ...input, name: input.name.trim(), description: input.description.trim() }))),
519
+ requiredInputs: JSON.stringify(normalizedInputs),
471
520
  reasoningModelKey, fastModelKey, systemPrompt, stepLimit: Number(stepLimit),
472
521
  turnStepLimit: Number(turnStepLimit), costLimit: Number(costLimit),
473
522
  ...agentHubTagsPayload(tags),
@@ -546,25 +595,27 @@ export function AgentRegistryEditorPage() {
546
595
  {field("Description", description, setDescription, "description")}<div className="agent-editor__field"><span>Icon</span><SolidIconPicker value={iconName} onChange={setIconName} /></div>
547
596
  </div>
548
597
  <AgentHubTagsField value={tags} onChange={setTags} disabled={creating || updating || isLoading || isFetching || isError} onBusyChange={setCreatingTag} />
549
- <section className="agent-editor__section"><div className="agent-editor__section-head"><div><h2>Required inputs</h2><p>Define the variables people must provide when starting this agent.</p></div>
550
- {inputs.length > 0 && <SolidButton type="button" variant="secondary" size="small" onClick={() => setInputs((current) => [...current, { name: "", description: "", dataType: "string" }])}><Plus size={15} /> Add input</SolidButton>}
598
+ <section className="agent-editor__section"><div className="agent-editor__section-head"><div><h2>Inputs</h2><p>Define the variables this agent can use. Mark inputs optional or provide a default value when people do not need to enter them.</p></div>
599
+ {inputs.length > 0 && <SolidButton type="button" variant="secondary" size="small" onClick={() => setInputs((current) => [...current, { name: "", description: "", dataType: "string", defaultValue: null, optional: false }])}><Plus size={15} /> Add input</SolidButton>}
551
600
  </div>
552
- {!inputs.length ? <div className="agent-editor__empty">This agent has no required inputs. <button type="button" onClick={() => setInputs([{ name: "", description: "", dataType: "string" }])}><Plus size={15} /> Add an input variable</button></div>
601
+ {!inputs.length ? <div className="agent-editor__empty">This agent has no inputs. <button type="button" onClick={() => setInputs([{ name: "", description: "", dataType: "string", defaultValue: null, optional: false }])}><Plus size={15} /> Add an input variable</button></div>
553
602
  : <div className="agent-editor__inputs">{inputs.map((input, index) => <div className="agent-editor__input-row" key={index}>
554
603
  <SolidInput aria-label={`Input ${index + 1} name`} placeholder="Variable name" value={input.name} onChange={(event) => setInputs((current) => current.map((item, i) => i === index ? { ...item, name: event.target.value } : item))} />
555
604
  <SolidInput aria-label={`Input ${index + 1} description`} placeholder="Description" value={input.description} onChange={(event) => setInputs((current) => current.map((item, i) => i === index ? { ...item, description: event.target.value } : item))} />
605
+ <SolidInput aria-label={`Input ${index + 1} default value`} placeholder="Default value" value={formatDefaultValue(input.defaultValue)} onChange={(event) => setInputs((current) => current.map((item, i) => i === index ? { ...item, defaultValue: event.target.value } : item))} />
556
606
  <select aria-label={`Input ${index + 1} data type`} value={input.dataType} onChange={(event) => setInputs((current) => current.map((item, i) => i === index ? { ...item, dataType: event.target.value } : item))}>
557
607
  {["string", "number", "integer", "boolean", "date", "datetime", "object", "array"].map((type) => <option key={type} value={type}>{type}</option>)}
558
608
  </select>
609
+ <label className="agent-editor__input-optional"><input type="checkbox" checked={input.optional} onChange={(event) => setInputs((current) => current.map((item, i) => i === index ? { ...item, optional: event.target.checked } : item))} /> Optional</label>
559
610
  <button type="button" aria-label={`Remove input ${index + 1}`} onClick={() => setInputs((current) => current.filter((_, i) => i !== index))}><Trash2 size={17} /></button>
560
611
  </div>)}</div>}
561
612
  {errors.inputs && <small className="agent-editor__error">{errors.inputs}</small>}</section>
562
- <section className="agent-editor__section"><h2>Models</h2><p>Choose any configured provider and model pair for each role. Both lists use the models enabled in AI settings.</p><div className="agent-editor__grid">
613
+ <section className="agent-editor__section agent-editor__models"><h2>Models</h2><p>Choose a configured provider and model for each role. Select Other to enter a model ID manually.</p><div className="agent-editor__grid">
563
614
  {([["Reasoning model", reasoningModelKey, setReasoningModelKey, "reasoningModelKey"], ["Fast model", fastModelKey, setFastModelKey, "fastModelKey"]] as const).map(([label, value, setter, key]) =>
564
- <label className="agent-editor__field" key={key}><span>{label} *</span><ModelPicker value={value} options={modelOptions} placeholder="Search providers and models…" onChange={(next) => setter(next)} />
565
- {errors[key] && <small className="agent-editor__error">{errors[key]}</small>}</label>)}
615
+ <div className="agent-editor__field" key={key}><span>{label}</span><ModelPicker value={value} options={modelOptions} providers={providerOptions} providerConfig={aiConfig.providers ?? {}} onChange={setter} />
616
+ {errors[key] && <small className="agent-editor__error">{errors[key]}</small>}</div>)}
566
617
  </div>{settingsError ? <p className="agent-editor__hint">Settings could not be loaded. Try refreshing this page.</p>
567
- : !modelOptions.length && <p className="agent-editor__hint">No configured models are available. Check the AI settings and your permission to view encrypted settings.</p>}</section>
618
+ : !providerOptions.length && <p className="agent-editor__hint">No enabled providers are available. Check the AI settings and your permission to view encrypted settings.</p>}</section>
568
619
  <section className="agent-editor__section agent-editor__workflow" aria-labelledby="agent-lifecycle-title">
569
620
  <div className="agent-editor__section-head"><div><h2 id="agent-lifecycle-title">Agent lifecycle</h2><p>Track this agent through its available stages. Select a stage to update its status.</p></div><div className="agent-editor__workflow-meta">{record?.configVersion != null && <span className="agent-editor__config-version" aria-label={`Configuration version ${record.configVersion}`}>Config v{record.configVersion}</span>}<SolidWorkflowStatusPill label={agentStatus} /></div></div>
570
621
  <div className="agent-editor__workflow-stages" aria-label={`Current agent stage: ${agentStatus}`}>
@@ -585,7 +636,8 @@ export function AgentRegistryEditorPage() {
585
636
  <small className="agent-editor__workflow-save-hint">Changing stage saves the current form and its linked skills, tools, roles, and secrets.</small>
586
637
  </section>
587
638
  </div> },
588
- { value: "persona", label: "Persona", content: <section className="agent-editor__section agent-editor__persona"><div className="agent-editor__section-head"><div><h2>System prompt *</h2><p>Describe the agent's role, behavior, and instructions in Markdown.</p></div></div>
639
+ { value: "persona", label: "Persona", content: <section className="agent-editor__section agent-editor__persona"><div className="agent-editor__section-head"><div><h2>System prompt *</h2><p>Describe the agent's role, behavior, and instructions in Markdown.</p></div>
640
+ {record?.id && <AgentPersonaHistory agentId={record.id} savedPrompt={record.systemPrompt ?? ""} refreshVersion={auditVersion} />}</div>
589
641
  <SolidCodeEditor value={systemPrompt} onChange={(value) => { setSystemPrompt(value ?? ""); setErrors((current) => ({ ...current, systemPrompt: "" })); }} language="markdown" fontSize={11} height="max(34rem, calc(100dvh - 18rem))" />
590
642
  {errors.systemPrompt && <small className="agent-editor__error">{errors.systemPrompt}</small>}</section> },
591
643
  { value: "skills", label: "Skills", content: <LinkPicker label="Skills" description="Skills available to this agent." options={skills.records} selected={linked(skillIds, skills.records, items(record?.agentSkills).map((link) => link.agentSkillRegistry).filter(Boolean))}
@@ -0,0 +1,2 @@
1
+ export declare function ArchivedChatterMessagesPage(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=ArchivedChatterMessagesPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ArchivedChatterMessagesPage.d.ts","sourceRoot":"","sources":["../../../../../src/routes/pages/admin/core/ArchivedChatterMessagesPage.tsx"],"names":[],"mappings":"AASA,wBAAgB,2BAA2B,4CAsF1C"}
@@ -0,0 +1,108 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
13
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
14
+ return new (P || (P = Promise))(function (resolve, reject) {
15
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
16
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
17
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
18
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
19
+ });
20
+ };
21
+ var __generator = (this && this.__generator) || function (thisArg, body) {
22
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
23
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
24
+ function verb(n) { return function (v) { return step([n, v]); }; }
25
+ function step(op) {
26
+ if (f) throw new TypeError("Generator is already executing.");
27
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
28
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
29
+ if (y = 0, t) op = [op[0] & 2, t.value];
30
+ switch (op[0]) {
31
+ case 0: case 1: t = op; break;
32
+ case 4: _.label++; return { value: op[1], done: false };
33
+ case 5: _.label++; y = op[1]; op = [0]; continue;
34
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
35
+ default:
36
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
37
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
38
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
39
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
40
+ if (t[2]) _.ops.pop();
41
+ _.trys.pop(); continue;
42
+ }
43
+ op = body.call(thisArg, _);
44
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
45
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
46
+ }
47
+ };
48
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
49
+ import React from 'react';
50
+ import qs from 'qs';
51
+ import { ChevronLeft, ChevronRight, Loader2 } from 'lucide-react';
52
+ import { SolidButton } from '../../../../components/shad-cn-ui';
53
+ import { useGetArchivedChatterMessagesQuery, useLazyGetArchivedChatterMessageQuery } from '../../../../redux/api/solidChatterMessageApi';
54
+ var PAGE_SIZE = 25;
55
+ export function ArchivedChatterMessagesPage() {
56
+ var _this = this;
57
+ var _a, _b, _c, _d, _e;
58
+ var _f = React.useState({ entityName: '', entityId: '', messageType: '', messageSubType: '', user: '', from: '', to: '' }), filters = _f[0], setFilters = _f[1];
59
+ var _g = React.useState(0), offset = _g[0], setOffset = _g[1];
60
+ var _h = React.useState(null), selectedId = _h[0], setSelectedId = _h[1];
61
+ var queryString = React.useMemo(function () {
62
+ var query = { limit: PAGE_SIZE, offset: offset };
63
+ var where = {};
64
+ if (filters.entityName.trim())
65
+ where.coModelName = { $containsi: filters.entityName.trim() };
66
+ if (filters.entityId.trim() && Number.isFinite(Number(filters.entityId)))
67
+ where.coModelEntityId = { $eq: Number(filters.entityId) };
68
+ if (filters.messageType)
69
+ where.messageType = { $eq: filters.messageType };
70
+ if (filters.messageSubType.trim())
71
+ where.messageSubType = { $containsi: filters.messageSubType.trim() };
72
+ if (filters.user.trim())
73
+ where.user = { fullName: { $containsi: filters.user.trim() } };
74
+ if (filters.from || filters.to) {
75
+ where.createdAt = {};
76
+ if (filters.from)
77
+ where.createdAt.$gte = new Date(filters.from).toISOString();
78
+ if (filters.to)
79
+ where.createdAt.$lte = new Date(filters.to).toISOString();
80
+ }
81
+ if (Object.keys(where).length)
82
+ query.filters = where;
83
+ query.sort = ['createdAt:DESC'];
84
+ return qs.stringify(query, { encodeValuesOnly: true });
85
+ }, [filters, offset]);
86
+ var _j = useGetArchivedChatterMessagesQuery(queryString), data = _j.data, isLoading = _j.isLoading, isFetching = _j.isFetching, error = _j.error;
87
+ var _k = useLazyGetArchivedChatterMessageQuery(), fetchOne = _k[0], _l = _k[1], detailData = _l.data, detailLoading = _l.isFetching;
88
+ var records = (_a = data === null || data === void 0 ? void 0 : data.records) !== null && _a !== void 0 ? _a : [];
89
+ var meta = (_b = data === null || data === void 0 ? void 0 : data.meta) !== null && _b !== void 0 ? _b : {};
90
+ var openRecord = function (id) { return __awaiter(_this, void 0, void 0, function () {
91
+ return __generator(this, function (_a) {
92
+ switch (_a.label) {
93
+ case 0:
94
+ setSelectedId(id);
95
+ return [4 /*yield*/, fetchOne(id)];
96
+ case 1:
97
+ _a.sent();
98
+ return [2 /*return*/];
99
+ }
100
+ });
101
+ }); };
102
+ var selected = detailData === null || detailData === void 0 ? void 0 : detailData.record;
103
+ return _jsxs("main", { className: "mx-auto flex w-full max-w-7xl flex-col gap-5 p-6", children: [_jsxs("header", { children: [_jsx("h1", { className: "m-0 text-2xl font-semibold", children: "Archived Messages" }), _jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Search chatter messages moved to the configured archive store." })] }), (data === null || data === void 0 ? void 0 : data.available) === false ? _jsxs("section", { className: "rounded-lg border p-6", role: "status", children: [_jsx("h2", { className: "m-0 text-lg font-semibold", children: "Chatter archival is not enabled" }), _jsx("p", { className: "mb-0 mt-2 text-sm text-muted-foreground", children: "Configure and register an IChatterMessageArchive provider in the consuming project to archive and browse messages." })] }) : _jsxs(_Fragment, { children: [_jsxs("section", { className: "grid grid-cols-1 gap-3 rounded-lg border p-4 sm:grid-cols-2 lg:grid-cols-7", "aria-label": "Archive filters", children: [_jsxs("label", { className: "flex flex-col gap-1 text-sm", children: ["Entity name", _jsx("input", { className: "rounded border px-3 py-2", value: filters.entityName, onChange: function (e) { setOffset(0); setFilters(__assign(__assign({}, filters), { entityName: e.target.value })); }, placeholder: "e.g. customer" })] }), _jsxs("label", { className: "flex flex-col gap-1 text-sm", children: ["Entity ID", _jsx("input", { className: "rounded border px-3 py-2", inputMode: "numeric", value: filters.entityId, onChange: function (e) { setOffset(0); setFilters(__assign(__assign({}, filters), { entityId: e.target.value })); }, placeholder: "Record ID" })] }), _jsxs("label", { className: "flex flex-col gap-1 text-sm", children: ["Message type", _jsxs("select", { className: "rounded border px-3 py-2", value: filters.messageType, onChange: function (e) { setOffset(0); setFilters(__assign(__assign({}, filters), { messageType: e.target.value })); }, children: [_jsx("option", { value: "", children: "All types" }), _jsx("option", { value: "audit", children: "Audit" }), _jsx("option", { value: "custom", children: "Custom" })] })] }), _jsxs("label", { className: "flex flex-col gap-1 text-sm", children: ["Message subtype", _jsx("input", { className: "rounded border px-3 py-2", value: filters.messageSubType, onChange: function (e) { setOffset(0); setFilters(__assign(__assign({}, filters), { messageSubType: e.target.value })); }, placeholder: "e.g. audit_update" })] }), _jsxs("label", { className: "flex flex-col gap-1 text-sm", children: ["Changed by", _jsx("input", { className: "rounded border px-3 py-2", value: filters.user, onChange: function (e) { setOffset(0); setFilters(__assign(__assign({}, filters), { user: e.target.value })); }, placeholder: "User name" })] }), _jsxs("label", { className: "flex flex-col gap-1 text-sm", children: ["From", _jsx("input", { className: "rounded border px-3 py-2", type: "datetime-local", value: filters.from, onChange: function (e) { setOffset(0); setFilters(__assign(__assign({}, filters), { from: e.target.value })); } })] }), _jsxs("label", { className: "flex flex-col gap-1 text-sm", children: ["To", _jsx("input", { className: "rounded border px-3 py-2", type: "datetime-local", value: filters.to, onChange: function (e) { setOffset(0); setFilters(__assign(__assign({}, filters), { to: e.target.value })); } })] })] }), error && _jsx("p", { role: "alert", className: "text-sm text-red-600", children: "Unable to load archived messages. Check provider availability and try again." }), _jsx("section", { className: "overflow-hidden rounded-lg border", children: isLoading ? _jsxs("div", { className: "flex items-center gap-2 p-8", children: [_jsx(Loader2, { className: "animate-spin", size: 18 }), "Loading archived messages\u2026"] }) : records.length === 0 ? _jsx("p", { className: "p-8 text-center text-sm text-muted-foreground", children: "No archived messages match these filters." }) : _jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full border-collapse text-left text-sm", children: [_jsx("thead", { className: "bg-muted/50", children: _jsxs("tr", { children: [_jsx("th", { className: "p-3", children: "Date" }), _jsx("th", { className: "p-3", children: "Entity" }), _jsx("th", { className: "p-3", children: "Entity ID" }), _jsx("th", { className: "p-3", children: "Type" }), _jsx("th", { className: "p-3", children: "User" }), _jsx("th", { className: "p-3", children: "Message" })] }) }), _jsx("tbody", { children: records.map(function (message) {
104
+ var _a;
105
+ return _jsxs("tr", { className: "border-t hover:bg-muted/30", children: [_jsx("td", { className: "whitespace-nowrap p-3", children: message.createdAt ? new Date(message.createdAt).toLocaleString() : '—' }), _jsx("td", { className: "p-3", children: message.modelDisplayName || message.coModelName }), _jsx("td", { className: "p-3", children: message.coModelEntityId }), _jsx("td", { className: "p-3", children: message.messageSubType || message.messageType }), _jsx("td", { className: "p-3", children: ((_a = message.user) === null || _a === void 0 ? void 0 : _a.fullName) || 'System' }), _jsx("td", { className: "max-w-md p-3", children: _jsx("button", { type: "button", className: "text-left text-primary underline", onClick: function () { return openRecord(message.id); }, children: message.messageBody || 'View message' }) })] }, message.id);
106
+ }) })] }) }) }), _jsxs("footer", { className: "flex items-center justify-between", children: [_jsxs("span", { className: "text-sm text-muted-foreground", children: [(_c = meta.totalRecords) !== null && _c !== void 0 ? _c : records.length, " archived messages", isFetching ? ' · Updating…' : ''] }), _jsxs("div", { className: "flex gap-2", children: [_jsxs(SolidButton, { variant: "outline", disabled: offset === 0 || isFetching, onClick: function () { return setOffset(Math.max(0, offset - PAGE_SIZE)); }, children: [_jsx(ChevronLeft, { size: 16 }), "Previous"] }), _jsxs(SolidButton, { variant: "outline", disabled: records.length < PAGE_SIZE || isFetching, onClick: function () { return setOffset(offset + PAGE_SIZE); }, children: ["Next", _jsx(ChevronRight, { size: 16 })] })] })] })] }), selectedId !== null && _jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4", role: "presentation", onClick: function () { return setSelectedId(null); }, children: _jsxs("section", { role: "dialog", "aria-modal": "true", "aria-label": "Archived chatter message", className: "max-h-[85vh] w-full max-w-3xl overflow-auto rounded-lg bg-background p-6 shadow-xl", onClick: function (e) { return e.stopPropagation(); }, children: [_jsxs("div", { className: "mb-4 flex items-start justify-between", children: [_jsxs("h2", { className: "m-0 text-xl font-semibold", children: ["Archived message #", selectedId] }), _jsx("button", { type: "button", className: "rounded px-2 py-1 hover:bg-muted", onClick: function () { return setSelectedId(null); }, children: "Close" })] }), detailLoading ? _jsx("p", { children: "Loading message\u2026" }) : selected ? _jsxs(_Fragment, { children: [_jsxs("dl", { className: "grid grid-cols-2 gap-3 text-sm", children: [_jsx("dt", { children: "Entity" }), _jsx("dd", { children: selected.modelDisplayName || selected.coModelName }), _jsx("dt", { children: "Entity ID" }), _jsx("dd", { children: selected.coModelEntityId }), _jsx("dt", { children: "Date" }), _jsx("dd", { children: selected.createdAt ? new Date(selected.createdAt).toLocaleString() : '—' }), _jsx("dt", { children: "User" }), _jsx("dd", { children: ((_d = selected.user) === null || _d === void 0 ? void 0 : _d.fullName) || 'System' }), _jsx("dt", { children: "Subtype" }), _jsx("dd", { children: selected.messageSubType })] }), _jsx("h3", { className: "mt-5 text-base font-semibold", children: "Message" }), _jsx("pre", { className: "whitespace-pre-wrap break-words rounded bg-muted p-3 text-sm", children: selected.messageBody || '' }), !!((_e = selected.chatterMessageDetails) === null || _e === void 0 ? void 0 : _e.length) && _jsxs(_Fragment, { children: [_jsx("h3", { className: "mt-5 text-base font-semibold", children: "Change details" }), _jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-left text-sm", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { className: "p-2", children: "Field" }), _jsx("th", { className: "p-2", children: "Previous" }), _jsx("th", { className: "p-2", children: "Current" })] }) }), _jsx("tbody", { children: selected.chatterMessageDetails.map(function (detail, index) { var _a, _b, _c, _d, _e; return _jsxs("tr", { className: "border-t", children: [_jsx("td", { className: "p-2", children: detail.fieldDisplayName || detail.fieldName }), _jsx("td", { className: "p-2", children: (_b = (_a = detail.oldValueDisplay) !== null && _a !== void 0 ? _a : detail.oldValue) !== null && _b !== void 0 ? _b : '—' }), _jsx("td", { className: "p-2", children: (_d = (_c = detail.newValueDisplay) !== null && _c !== void 0 ? _c : detail.newValue) !== null && _d !== void 0 ? _d : '—' })] }, (_e = detail.id) !== null && _e !== void 0 ? _e : index); }) })] }) })] })] }) : _jsx("p", { role: "alert", children: "Could not load this archived message." })] }) })] });
107
+ }
108
+ //# sourceMappingURL=ArchivedChatterMessagesPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ArchivedChatterMessagesPage.js","sourceRoot":"","sources":["../../../../../src/routes/pages/admin/core/ArchivedChatterMessagesPage.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport qs from 'qs';\nimport { ChevronLeft, ChevronRight, Loader2 } from 'lucide-react';\nimport { SolidButton } from '../../../../components/shad-cn-ui';\nimport { useGetArchivedChatterMessagesQuery, useLazyGetArchivedChatterMessageQuery } from '../../../../redux/api/solidChatterMessageApi';\n\nconst PAGE_SIZE = 25;\ntype Filters = { entityName: string; entityId: string; messageType: string; messageSubType: string; user: string; from: string; to: string };\n\nexport function ArchivedChatterMessagesPage() {\n const [filters, setFilters] = React.useState<Filters>({ entityName: '', entityId: '', messageType: '', messageSubType: '', user: '', from: '', to: '' });\n const [offset, setOffset] = React.useState(0);\n const [selectedId, setSelectedId] = React.useState<number | null>(null);\n\n const queryString = React.useMemo(() => {\n const query: any = { limit: PAGE_SIZE, offset };\n const where: Record<string, any> = {};\n if (filters.entityName.trim()) where.coModelName = { $containsi: filters.entityName.trim() };\n if (filters.entityId.trim() && Number.isFinite(Number(filters.entityId))) where.coModelEntityId = { $eq: Number(filters.entityId) };\n if (filters.messageType) where.messageType = { $eq: filters.messageType };\n if (filters.messageSubType.trim()) where.messageSubType = { $containsi: filters.messageSubType.trim() };\n if (filters.user.trim()) where.user = { fullName: { $containsi: filters.user.trim() } };\n if (filters.from || filters.to) {\n where.createdAt = {};\n if (filters.from) where.createdAt.$gte = new Date(filters.from).toISOString();\n if (filters.to) where.createdAt.$lte = new Date(filters.to).toISOString();\n }\n if (Object.keys(where).length) query.filters = where;\n query.sort = ['createdAt:DESC'];\n return qs.stringify(query, { encodeValuesOnly: true });\n }, [filters, offset]);\n\n const { data, isLoading, isFetching, error } = useGetArchivedChatterMessagesQuery(queryString);\n const [fetchOne, { data: detailData, isFetching: detailLoading }] = useLazyGetArchivedChatterMessageQuery();\n const records = data?.records ?? [];\n const meta = data?.meta ?? {};\n\n const openRecord = async (id: number) => {\n setSelectedId(id);\n await fetchOne(id);\n };\n const selected = detailData?.record;\n\n return <main className=\"mx-auto flex w-full max-w-7xl flex-col gap-5 p-6\">\n <header>\n <h1 className=\"m-0 text-2xl font-semibold\">Archived Messages</h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">Search chatter messages moved to the configured archive store.</p>\n </header>\n\n {data?.available === false ? <section className=\"rounded-lg border p-6\" role=\"status\">\n <h2 className=\"m-0 text-lg font-semibold\">Chatter archival is not enabled</h2>\n <p className=\"mb-0 mt-2 text-sm text-muted-foreground\">Configure and register an IChatterMessageArchive provider in the consuming project to archive and browse messages.</p>\n </section> : <>\n <section className=\"grid grid-cols-1 gap-3 rounded-lg border p-4 sm:grid-cols-2 lg:grid-cols-7\" aria-label=\"Archive filters\">\n <label className=\"flex flex-col gap-1 text-sm\">Entity name<input className=\"rounded border px-3 py-2\" value={filters.entityName} onChange={e => { setOffset(0); setFilters({ ...filters, entityName: e.target.value }); }} placeholder=\"e.g. customer\" /></label>\n <label className=\"flex flex-col gap-1 text-sm\">Entity ID<input className=\"rounded border px-3 py-2\" inputMode=\"numeric\" value={filters.entityId} onChange={e => { setOffset(0); setFilters({ ...filters, entityId: e.target.value }); }} placeholder=\"Record ID\" /></label>\n <label className=\"flex flex-col gap-1 text-sm\">Message type<select className=\"rounded border px-3 py-2\" value={filters.messageType} onChange={e => { setOffset(0); setFilters({ ...filters, messageType: e.target.value }); }}><option value=\"\">All types</option><option value=\"audit\">Audit</option><option value=\"custom\">Custom</option></select></label>\n <label className=\"flex flex-col gap-1 text-sm\">Message subtype<input className=\"rounded border px-3 py-2\" value={filters.messageSubType} onChange={e => { setOffset(0); setFilters({ ...filters, messageSubType: e.target.value }); }} placeholder=\"e.g. audit_update\" /></label>\n <label className=\"flex flex-col gap-1 text-sm\">Changed by<input className=\"rounded border px-3 py-2\" value={filters.user} onChange={e => { setOffset(0); setFilters({ ...filters, user: e.target.value }); }} placeholder=\"User name\" /></label>\n <label className=\"flex flex-col gap-1 text-sm\">From<input className=\"rounded border px-3 py-2\" type=\"datetime-local\" value={filters.from} onChange={e => { setOffset(0); setFilters({ ...filters, from: e.target.value }); }} /></label>\n <label className=\"flex flex-col gap-1 text-sm\">To<input className=\"rounded border px-3 py-2\" type=\"datetime-local\" value={filters.to} onChange={e => { setOffset(0); setFilters({ ...filters, to: e.target.value }); }} /></label>\n </section>\n\n {error && <p role=\"alert\" className=\"text-sm text-red-600\">Unable to load archived messages. Check provider availability and try again.</p>}\n <section className=\"overflow-hidden rounded-lg border\">\n {isLoading ? <div className=\"flex items-center gap-2 p-8\"><Loader2 className=\"animate-spin\" size={18} />Loading archived messages…</div> : records.length === 0 ? <p className=\"p-8 text-center text-sm text-muted-foreground\">No archived messages match these filters.</p> : <div className=\"overflow-x-auto\">\n <table className=\"w-full border-collapse text-left text-sm\">\n <thead className=\"bg-muted/50\"><tr><th className=\"p-3\">Date</th><th className=\"p-3\">Entity</th><th className=\"p-3\">Entity ID</th><th className=\"p-3\">Type</th><th className=\"p-3\">User</th><th className=\"p-3\">Message</th></tr></thead>\n <tbody>{records.map((message: any) => <tr key={message.id} className=\"border-t hover:bg-muted/30\">\n <td className=\"whitespace-nowrap p-3\">{message.createdAt ? new Date(message.createdAt).toLocaleString() : '—'}</td>\n <td className=\"p-3\">{message.modelDisplayName || message.coModelName}</td><td className=\"p-3\">{message.coModelEntityId}</td>\n <td className=\"p-3\">{message.messageSubType || message.messageType}</td><td className=\"p-3\">{message.user?.fullName || 'System'}</td>\n <td className=\"max-w-md p-3\"><button type=\"button\" className=\"text-left text-primary underline\" onClick={() => openRecord(message.id)}>{message.messageBody || 'View message'}</button></td>\n </tr>)}</tbody>\n </table>\n </div>}\n </section>\n\n <footer className=\"flex items-center justify-between\">\n <span className=\"text-sm text-muted-foreground\">{meta.totalRecords ?? records.length} archived messages{isFetching ? ' · Updating…' : ''}</span>\n <div className=\"flex gap-2\"><SolidButton variant=\"outline\" disabled={offset === 0 || isFetching} onClick={() => setOffset(Math.max(0, offset - PAGE_SIZE))}><ChevronLeft size={16} />Previous</SolidButton><SolidButton variant=\"outline\" disabled={records.length < PAGE_SIZE || isFetching} onClick={() => setOffset(offset + PAGE_SIZE)}>Next<ChevronRight size={16} /></SolidButton></div>\n </footer>\n </>}\n\n {selectedId !== null && <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4\" role=\"presentation\" onClick={() => setSelectedId(null)}>\n <section role=\"dialog\" aria-modal=\"true\" aria-label=\"Archived chatter message\" className=\"max-h-[85vh] w-full max-w-3xl overflow-auto rounded-lg bg-background p-6 shadow-xl\" onClick={e => e.stopPropagation()}>\n <div className=\"mb-4 flex items-start justify-between\"><h2 className=\"m-0 text-xl font-semibold\">Archived message #{selectedId}</h2><button type=\"button\" className=\"rounded px-2 py-1 hover:bg-muted\" onClick={() => setSelectedId(null)}>Close</button></div>\n {detailLoading ? <p>Loading message…</p> : selected ? <>\n <dl className=\"grid grid-cols-2 gap-3 text-sm\"><dt>Entity</dt><dd>{selected.modelDisplayName || selected.coModelName}</dd><dt>Entity ID</dt><dd>{selected.coModelEntityId}</dd><dt>Date</dt><dd>{selected.createdAt ? new Date(selected.createdAt).toLocaleString() : '—'}</dd><dt>User</dt><dd>{selected.user?.fullName || 'System'}</dd><dt>Subtype</dt><dd>{selected.messageSubType}</dd></dl>\n <h3 className=\"mt-5 text-base font-semibold\">Message</h3><pre className=\"whitespace-pre-wrap break-words rounded bg-muted p-3 text-sm\">{selected.messageBody || ''}</pre>\n {!!selected.chatterMessageDetails?.length && <><h3 className=\"mt-5 text-base font-semibold\">Change details</h3><div className=\"overflow-x-auto\"><table className=\"w-full text-left text-sm\"><thead><tr><th className=\"p-2\">Field</th><th className=\"p-2\">Previous</th><th className=\"p-2\">Current</th></tr></thead><tbody>{selected.chatterMessageDetails.map((detail: any, index: number) => <tr className=\"border-t\" key={detail.id ?? index}><td className=\"p-2\">{detail.fieldDisplayName || detail.fieldName}</td><td className=\"p-2\">{detail.oldValueDisplay ?? detail.oldValue ?? '—'}</td><td className=\"p-2\">{detail.newValueDisplay ?? detail.newValue ?? '—'}</td></tr>)}</tbody></table></div></>}\n </> : <p role=\"alert\">Could not load this archived message.</p>}\n </section>\n </div>}\n </main>;\n}\n"]}