@swiss-ai-hub/web 0.290.11

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 (313) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +479 -0
  3. package/app.config.ts +1 -0
  4. package/app.vue +52 -0
  5. package/assets/css/main.css +4 -0
  6. package/assets/images/logo.png +0 -0
  7. package/components/Agent/Avatar.vue +40 -0
  8. package/components/Agent/Card.vue +139 -0
  9. package/components/Agent/Configuration.vue +20 -0
  10. package/components/Agent/CreateModal.vue +287 -0
  11. package/components/Agent/EmptyCard.vue +35 -0
  12. package/components/Agent/List.vue +85 -0
  13. package/components/Agent/TemplateCard.vue +58 -0
  14. package/components/AppLoader.vue +55 -0
  15. package/components/Chat/Message.vue +90 -0
  16. package/components/Chat/SourceNodes.vue +120 -0
  17. package/components/Chat/Thread.vue +134 -0
  18. package/components/Costs/Table.vue +56 -0
  19. package/components/Dashboard/Component/BarChart.vue +46 -0
  20. package/components/Dashboard/Component/LineChart.vue +138 -0
  21. package/components/Dashboard/Component/Number.vue +31 -0
  22. package/components/Dashboard/Grid.vue +214 -0
  23. package/components/Dashboard/Item.vue +75 -0
  24. package/components/Dashboard/Trend.vue +34 -0
  25. package/components/Display/List/DisplayList.vue +93 -0
  26. package/components/Evaluation/Dataset/Card.vue +70 -0
  27. package/components/Evaluation/Dataset/Create.vue +81 -0
  28. package/components/Evaluation/Dataset/Edit.vue +132 -0
  29. package/components/Event/Display/AddMemoryToChatHistoryEvent.vue +60 -0
  30. package/components/Event/Display/AgentInTheLoopRequestEvent.vue +56 -0
  31. package/components/Event/Display/AgentInTheLoopResponseEvent.vue +17 -0
  32. package/components/Event/Display/Base.vue +125 -0
  33. package/components/Event/Display/BaseRetrieveMemoryEvent.vue +101 -0
  34. package/components/Event/Display/BaseStoreMemoryEvent.vue +182 -0
  35. package/components/Event/Display/ChunkEvent.vue +40 -0
  36. package/components/Event/Display/EmbeddingEvent.vue +25 -0
  37. package/components/Event/Display/ExceptionEvent.vue +21 -0
  38. package/components/Event/Display/GuardAcceptEvent.vue +25 -0
  39. package/components/Event/Display/GuardEvent.vue +17 -0
  40. package/components/Event/Display/GuardRejectionEvent.vue +25 -0
  41. package/components/Event/Display/HumanInTheLoopRequestEvent.vue +53 -0
  42. package/components/Event/Display/HumanInTheLoopResponseEvent.vue +40 -0
  43. package/components/Event/Display/LLMCostEvent.vue +25 -0
  44. package/components/Event/Display/LLMEvent.vue +92 -0
  45. package/components/Event/Display/LimitChatHistoryEvent.vue +60 -0
  46. package/components/Event/Display/RAGFailureStopEvent.vue +28 -0
  47. package/components/Event/Display/RAGStartEvent.vue +77 -0
  48. package/components/Event/Display/RAGSuccessStopEvent.vue +16 -0
  49. package/components/Event/Display/RawDataContent.vue +69 -0
  50. package/components/Event/Display/RerankerEvent.vue +39 -0
  51. package/components/Event/Display/RetrieverEvent.vue +22 -0
  52. package/components/Event/Display/RouterEvent.vue +54 -0
  53. package/components/Event/Display/StandaloneQuestionCondenserEvent.vue +38 -0
  54. package/components/Event/Display/StopEvent.vue +16 -0
  55. package/components/Event/Display/ThoughtEvent.vue +20 -0
  56. package/components/Event/Display/ToolEvent.vue +38 -0
  57. package/components/Event/Display/UnknownEvent.vue +17 -0
  58. package/components/Event/Display/UserMessageEvent.vue +35 -0
  59. package/components/Event/List/EventList.vue +249 -0
  60. package/components/Event/Statistics.vue +49 -0
  61. package/components/Event/Timeseries.vue +224 -0
  62. package/components/FormKit/AgentSelector.vue +307 -0
  63. package/components/FormKit/ChipsInput.vue +62 -0
  64. package/components/FormKit/DynamicConfiguration.vue +155 -0
  65. package/components/FormKit/IconSelector.vue +72 -0
  66. package/components/FormKit/KnowledgeDatabaseSelector.vue +92 -0
  67. package/components/FormKit/LocaleInput.vue +150 -0
  68. package/components/FormKit/ModelSelect.vue +110 -0
  69. package/components/FormKit/Repeater.vue +93 -0
  70. package/components/FormKit/VectorStoreInput.vue +247 -0
  71. package/components/Knowledge/Document/List.vue +140 -0
  72. package/components/Knowledge/Document/Overview.vue +28 -0
  73. package/components/Knowledge/Document/UploadModal.vue +298 -0
  74. package/components/Knowledge/Document/WithNodes.vue +105 -0
  75. package/components/Knowledge/Namespace/Card.vue +108 -0
  76. package/components/Knowledge/Namespace/CreateModal.vue +203 -0
  77. package/components/Knowledge/Namespace/EditModal.vue +134 -0
  78. package/components/Knowledge/Namespace/EmptyCard.vue +35 -0
  79. package/components/Knowledge/Node/Content.vue +71 -0
  80. package/components/Markdown/Renderer.vue +87 -0
  81. package/components/Memory/DetailPage.vue +48 -0
  82. package/components/Memory/Edit.vue +241 -0
  83. package/components/Memory/Graph.vue +318 -0
  84. package/components/Memory/List.vue +155 -0
  85. package/components/Memory/MemoryManagementPage.vue +178 -0
  86. package/components/Memory/OpenWebUIContent.vue +96 -0
  87. package/components/Memory/PageLayout.vue +72 -0
  88. package/components/Models/ModelDetailsPanel.vue +250 -0
  89. package/components/Models/NamespaceCard.vue +79 -0
  90. package/components/Navigation/Left.vue +85 -0
  91. package/components/Navigation/Top.vue +31 -0
  92. package/components/Notification/Item.vue +88 -0
  93. package/components/Notification/NotificationsOverlay.vue +164 -0
  94. package/components/Process/Card.vue +119 -0
  95. package/components/Process/Configuration.vue +20 -0
  96. package/components/Process/CreateModal.vue +276 -0
  97. package/components/Process/EmptyCard.vue +35 -0
  98. package/components/Process/Form.vue +153 -0
  99. package/components/Process/Starts.vue +44 -0
  100. package/components/Process/Walkthrough/List.vue +162 -0
  101. package/components/Role/AccessRulesEditor.vue +132 -0
  102. package/components/Role/Card.vue +68 -0
  103. package/components/Role/Create.vue +55 -0
  104. package/components/Role/Edit.vue +82 -0
  105. package/components/Role/UsageLimitsEditor.vue +225 -0
  106. package/components/Service/Selection.vue +148 -0
  107. package/components/Structural/Column.vue +74 -0
  108. package/components/Structural/Screen.vue +10 -0
  109. package/components/Structural/Substructure.vue +5 -0
  110. package/components/Tenant/Switcher.vue +102 -0
  111. package/components/Thread/Details.vue +135 -0
  112. package/components/Thread/Hierarchy.vue +136 -0
  113. package/components/Thread/Info.vue +41 -0
  114. package/components/Thread/List.vue +136 -0
  115. package/components/User/Bar.vue +74 -0
  116. package/components/User/List.vue +86 -0
  117. package/components/User/RoleChips.vue +83 -0
  118. package/components/User/Settings.vue +79 -0
  119. package/components/Workflow/Modal.vue +39 -0
  120. package/components/Workflow/NodeCard.vue +41 -0
  121. package/components/Workflow/StartNode.vue +24 -0
  122. package/components/Workflow/StepNode.vue +27 -0
  123. package/components/Workflow/StopNode.vue +24 -0
  124. package/components/Workflow/Visualization.vue +265 -0
  125. package/components/mdc/MarkdownFigure.vue +9 -0
  126. package/components/mdc/MarkdownTable.vue +9 -0
  127. package/components/mdc/ResolveImageComponent.vue +58 -0
  128. package/composables/agent/useAgentClass.ts +27 -0
  129. package/composables/agent/useAgentClassInstances.ts +27 -0
  130. package/composables/agent/useAgentClasses.ts +27 -0
  131. package/composables/agent/useAgentIconFromThread.ts +8 -0
  132. package/composables/agent/useAgentInstance.ts +28 -0
  133. package/composables/agent/useAgentInstanceThreads.ts +76 -0
  134. package/composables/agent/useAgentInstances.ts +25 -0
  135. package/composables/agent/useAgentNavigation.ts +35 -0
  136. package/composables/agent/useCreateAgentInstance.ts +33 -0
  137. package/composables/agent/useDeleteAgentInstance.ts +31 -0
  138. package/composables/agent/useUpdateAgentInstance.ts +40 -0
  139. package/composables/auth/useAuth.ts +54 -0
  140. package/composables/auth/useAuthProviders.ts +14 -0
  141. package/composables/chat/useChatCompletions.ts +30 -0
  142. package/composables/dashboard/useAgentNameFromDashboardWidget.ts +27 -0
  143. package/composables/dashboard/useDashboardComponent.ts +27 -0
  144. package/composables/dashboard/useSaveDashboard.ts +21 -0
  145. package/composables/document/useCreateNamespace.ts +26 -0
  146. package/composables/document/useDatabases.ts +23 -0
  147. package/composables/document/useDocument.ts +29 -0
  148. package/composables/document/useDocumentUrl.ts +20 -0
  149. package/composables/document/useDocuments.ts +107 -0
  150. package/composables/document/useNodes.ts +29 -0
  151. package/composables/document/useSummaryNodes.ts +32 -0
  152. package/composables/document/useUpdateNamespace.ts +22 -0
  153. package/composables/evaluation/useCreateDataset.ts +19 -0
  154. package/composables/evaluation/useDataset.ts +26 -0
  155. package/composables/evaluation/useDatasets.ts +25 -0
  156. package/composables/evaluation/useUpdateDataset.ts +23 -0
  157. package/composables/event/useBasicEventStatistics.ts +83 -0
  158. package/composables/event/useEventColor.ts +25 -0
  159. package/composables/event/useEventComponent.ts +87 -0
  160. package/composables/event/useEventTimeseries.ts +39 -0
  161. package/composables/event/useEventTimeseriesStats.ts +26 -0
  162. package/composables/file/useFileUpload.ts +91 -0
  163. package/composables/file/useSupportedFileTypes.ts +22 -0
  164. package/composables/form/useCreateInstanceForm.ts +251 -0
  165. package/composables/form/useFormKitTransform.ts +753 -0
  166. package/composables/memory/useMemoryCRUD.ts +88 -0
  167. package/composables/memory/useMemoryFactory.ts +319 -0
  168. package/composables/memory/useMemorySearchFilter.ts +74 -0
  169. package/composables/models/useModelsList.ts +24 -0
  170. package/composables/models/useSingleModel.ts +30 -0
  171. package/composables/notification/useNotificationPoller.ts +58 -0
  172. package/composables/notification/useNotifications.ts +57 -0
  173. package/composables/notification/useUpdateMultipleNotifications.ts +17 -0
  174. package/composables/notification/useUpdateNotification.ts +17 -0
  175. package/composables/process/useCreateProcessInstance.ts +32 -0
  176. package/composables/process/useDeleteProcessInstance.ts +31 -0
  177. package/composables/process/useProcessClasses.ts +27 -0
  178. package/composables/process/useProcessInstance.ts +28 -0
  179. package/composables/process/useProcessInstances.ts +27 -0
  180. package/composables/process/useProcessWalkthroughs.ts +73 -0
  181. package/composables/process/useSendProcessStartForm.ts +43 -0
  182. package/composables/process/useUpdateProcessInstance.ts +40 -0
  183. package/composables/role/useCreateRole.ts +19 -0
  184. package/composables/role/useDeleteRole.ts +21 -0
  185. package/composables/role/useRole.ts +30 -0
  186. package/composables/role/useRoles.ts +25 -0
  187. package/composables/role/useUpdateRole.ts +22 -0
  188. package/composables/suite/useApps.ts +31 -0
  189. package/composables/suite/useSuite.ts +26 -0
  190. package/composables/tenant/useActiveTenant.ts +27 -0
  191. package/composables/tenant/useSysadminNavigation.ts +19 -0
  192. package/composables/tenant/useTenant.ts +38 -0
  193. package/composables/tenant/useTenantMemberships.ts +15 -0
  194. package/composables/tenant/useTenantPath.ts +20 -0
  195. package/composables/tenant/useTenantPolling.ts +30 -0
  196. package/composables/tenant/useTenantReady.ts +12 -0
  197. package/composables/theme/useDarkMode.ts +5 -0
  198. package/composables/thread/useThread.ts +27 -0
  199. package/composables/thread/useThreadEvents.ts +91 -0
  200. package/composables/thread/useThreadUtils.ts +49 -0
  201. package/composables/thread/useThreads.ts +64 -0
  202. package/composables/thread/useThreadsInfinite.ts +56 -0
  203. package/composables/translation/useTranslate.ts +20 -0
  204. package/composables/useRouteReady.ts +21 -0
  205. package/composables/useTimeAgo.ts +40 -0
  206. package/composables/user/useAssignRoleToUser.ts +22 -0
  207. package/composables/user/useMyUser.ts +25 -0
  208. package/composables/user/useRevokeRoleFromUser.ts +21 -0
  209. package/composables/user/useUser.ts +30 -0
  210. package/composables/user/useUsers.ts +63 -0
  211. package/composables/utils/useJsonTree.ts +138 -0
  212. package/formkit.config.ts +44 -0
  213. package/i18n/locales/de.yaml +815 -0
  214. package/i18n/locales/en.yaml +804 -0
  215. package/i18n/locales/fr.yaml +812 -0
  216. package/i18n/locales/it.yaml +808 -0
  217. package/layouts/anonymous.vue +8 -0
  218. package/layouts/default.vue +116 -0
  219. package/middleware/auth.global.ts +62 -0
  220. package/nuxt.config.ts +145 -0
  221. package/package.json +114 -0
  222. package/pages/[tenant]/index.vue +31 -0
  223. package/pages/[tenant]/notifications/index.vue +235 -0
  224. package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/chat.vue +67 -0
  225. package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/configuration.vue +122 -0
  226. package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/memories/[memory_id].vue +3 -0
  227. package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/memories.vue +20 -0
  228. package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/overview.vue +72 -0
  229. package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/threads.vue +52 -0
  230. package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/workflow.vue +19 -0
  231. package/pages/[tenant]/service/agents/[agent_class]-[agent_id].vue +63 -0
  232. package/pages/[tenant]/service/agents/templates.vue +102 -0
  233. package/pages/[tenant]/service/agents.vue +185 -0
  234. package/pages/[tenant]/service/datasets/[dataset_id].vue +81 -0
  235. package/pages/[tenant]/service/datasets.vue +53 -0
  236. package/pages/[tenant]/service/health/index.vue +3 -0
  237. package/pages/[tenant]/service/knowledge/[db]/[namespace]/[document_id]/nodes.vue +20 -0
  238. package/pages/[tenant]/service/knowledge/[db]/[namespace]/[document_id]/overview.vue +40 -0
  239. package/pages/[tenant]/service/knowledge/[db]/[namespace]/[document_id]/summary.vue +88 -0
  240. package/pages/[tenant]/service/knowledge/[db]/[namespace]/[document_id].vue +48 -0
  241. package/pages/[tenant]/service/knowledge/[db]/[namespace].vue +144 -0
  242. package/pages/[tenant]/service/knowledge.vue +126 -0
  243. package/pages/[tenant]/service/models/[model_name].vue +84 -0
  244. package/pages/[tenant]/service/models.vue +61 -0
  245. package/pages/[tenant]/service/my-account.vue +117 -0
  246. package/pages/[tenant]/service/openai/[thread_id]/[display_id]/memories.vue +66 -0
  247. package/pages/[tenant]/service/openai/[thread_id]/[display_id]/sources.vue +100 -0
  248. package/pages/[tenant]/service/openai/[thread_id]/[display_id]/tracing.vue +49 -0
  249. package/pages/[tenant]/service/openai.vue +101 -0
  250. package/pages/[tenant]/service/organization-memories/graph.vue +97 -0
  251. package/pages/[tenant]/service/organization-memories/list/[memory_id].vue +3 -0
  252. package/pages/[tenant]/service/organization-memories/list.vue +150 -0
  253. package/pages/[tenant]/service/organization-memories.vue +3 -0
  254. package/pages/[tenant]/service/processes/[process_class]-[process_id]/[process_walkthrough_id].vue +7 -0
  255. package/pages/[tenant]/service/processes/[process_class]-[process_id]/configuration.vue +106 -0
  256. package/pages/[tenant]/service/processes/[process_class]-[process_id]/overview.vue +67 -0
  257. package/pages/[tenant]/service/processes/[process_class]-[process_id]/start.vue +26 -0
  258. package/pages/[tenant]/service/processes/[process_class]-[process_id]/walkthroughs/[process_walkthrough_id]/overview.vue +14 -0
  259. package/pages/[tenant]/service/processes/[process_class]-[process_id]/walkthroughs.vue +54 -0
  260. package/pages/[tenant]/service/processes/[process_class]-[process_id].vue +60 -0
  261. package/pages/[tenant]/service/processes.vue +129 -0
  262. package/pages/[tenant]/service/roles/[role_id].vue +54 -0
  263. package/pages/[tenant]/service/roles.vue +84 -0
  264. package/pages/[tenant]/service/threads/[thread_id]/chat.vue +51 -0
  265. package/pages/[tenant]/service/threads/[thread_id]/display/[display_id].vue +21 -0
  266. package/pages/[tenant]/service/threads/[thread_id]/display.vue +29 -0
  267. package/pages/[tenant]/service/threads/[thread_id]/hierarchy.vue +14 -0
  268. package/pages/[tenant]/service/threads/[thread_id]/memories/[memory_id].vue +3 -0
  269. package/pages/[tenant]/service/threads/[thread_id]/memories.vue +19 -0
  270. package/pages/[tenant]/service/threads/[thread_id]/overview.vue +100 -0
  271. package/pages/[tenant]/service/threads/[thread_id].vue +54 -0
  272. package/pages/[tenant]/service/threads.vue +52 -0
  273. package/pages/[tenant]/service/user-memories/graph.vue +97 -0
  274. package/pages/[tenant]/service/user-memories/list/[memory_id].vue +3 -0
  275. package/pages/[tenant]/service/user-memories/list.vue +150 -0
  276. package/pages/[tenant]/service/user-memories.vue +3 -0
  277. package/pages/[tenant]/service/users/[user_id].vue +117 -0
  278. package/pages/[tenant]/service/users.vue +88 -0
  279. package/pages/auth/callback.vue +52 -0
  280. package/pages/auth/login.vue +80 -0
  281. package/pages/auth/renew.vue +24 -0
  282. package/pages/index.vue +59 -0
  283. package/pages/select-tenant.vue +76 -0
  284. package/plugins/0.runtime-config.client.ts +55 -0
  285. package/plugins/apexcharts.client.ts +5 -0
  286. package/plugins/api-client.client.ts +38 -0
  287. package/plugins/dark-mode.client.ts +12 -0
  288. package/plugins/keycloak-client.ts +41 -0
  289. package/plugins/oidc-client.ts +78 -0
  290. package/sdk/client/client/client.gen.ts +237 -0
  291. package/sdk/client/client/index.ts +24 -0
  292. package/sdk/client/client/types.gen.ts +213 -0
  293. package/sdk/client/client/utils.gen.ts +407 -0
  294. package/sdk/client/client.gen.ts +25 -0
  295. package/sdk/client/core/auth.gen.ts +42 -0
  296. package/sdk/client/core/bodySerializer.gen.ts +96 -0
  297. package/sdk/client/core/params.gen.ts +181 -0
  298. package/sdk/client/core/pathSerializer.gen.ts +180 -0
  299. package/sdk/client/core/queryKeySerializer.gen.ts +136 -0
  300. package/sdk/client/core/serverSentEvents.gen.ts +265 -0
  301. package/sdk/client/core/types.gen.ts +118 -0
  302. package/sdk/client/core/utils.gen.ts +143 -0
  303. package/sdk/client/index.ts +1013 -0
  304. package/sdk/client/schemas.gen.ts +35395 -0
  305. package/sdk/client/sdk.gen.ts +3438 -0
  306. package/sdk/client/transformers.gen.ts +143 -0
  307. package/sdk/client/types.gen.ts +27567 -0
  308. package/tailwind.config.mjs +27 -0
  309. package/themes/aihub-theme.ts +125 -0
  310. package/types/DashboardWidget.ts +13 -0
  311. package/types/EventChartInput.ts +7 -0
  312. package/types/NavItem.ts +6 -0
  313. package/types/TimeseriesInput.ts +7 -0
@@ -0,0 +1,265 @@
1
+ <template>
2
+ <VueFlow
3
+ :nodes="nodes"
4
+ :edges="edges"
5
+ :min-zoom="0.2"
6
+ :max-zoom="4"
7
+ :nodes-connectable="false"
8
+ fit-view-on-init
9
+ class="size-full"
10
+ >
11
+ <Background />
12
+
13
+ <template #node-start="{ id, data }">
14
+ <WorkflowStartNode
15
+ :id="id"
16
+ :data="data"
17
+ />
18
+ </template>
19
+
20
+ <template #node-step="{ id, data }">
21
+ <WorkflowStepNode
22
+ :id="id"
23
+ :data="data"
24
+ />
25
+ </template>
26
+
27
+ <template #node-stop="{ id, data }">
28
+ <WorkflowStopNode
29
+ :id="id"
30
+ :data="data"
31
+ />
32
+ </template>
33
+ </VueFlow>
34
+ </template>
35
+
36
+ <script setup lang="ts">
37
+ import { Background } from '@vue-flow/background'
38
+ import { VueFlow, MarkerType, Position, useVueFlow } from '@vue-flow/core'
39
+ import { computed, onBeforeUnmount, onMounted } from 'vue'
40
+
41
+ import '@vue-flow/core/dist/style.css'
42
+ import '@vue-flow/core/dist/theme-default.css'
43
+
44
+ import type { WorkflowGraph } from '@core/sdk/client'
45
+
46
+ const NODE_WIDTH = 298
47
+ const NODE_HEIGHT = 100
48
+ const ROW_GAP = 80
49
+ const COL_GAP = 80
50
+
51
+ const props = defineProps<{
52
+ graphData: WorkflowGraph
53
+ }>()
54
+
55
+ const { updateNodeInternals, fitView } = useVueFlow()
56
+
57
+ // Re-measure handle positions after the modal's open animation has settled.
58
+ // Without this, vue-flow's initial handleBounds are taken mid-animation and end
59
+ // up ~10px off-center, shifting edge endpoints sideways from the actual handles.
60
+ // The handle is cleared on unmount so a quick close-during-animation won't call
61
+ // updateNodeInternals/fitView on a disposed VueFlow instance.
62
+ let settleTimer: ReturnType<typeof setTimeout> | null = null
63
+ onMounted(() => {
64
+ settleTimer = setTimeout(() => {
65
+ updateNodeInternals(props.graphData.nodes.map(n => n.id))
66
+ fitView({ padding: 0.15 })
67
+ settleTimer = null
68
+ }, 350)
69
+ })
70
+ onBeforeUnmount(() => {
71
+ if (settleTimer !== null) {
72
+ clearTimeout(settleTimer)
73
+ settleTimer = null
74
+ }
75
+ })
76
+
77
+ const COL_PITCH = NODE_WIDTH + COL_GAP
78
+ const ROW_PITCH = NODE_HEIGHT + ROW_GAP
79
+
80
+ type Adjacency = Map<string, string[]>
81
+ type GridSlot = { row: number, col: number }
82
+ type ColumnCount = 1 | 2 | 3
83
+
84
+ const chooseColumnCount = (middleCount: number): ColumnCount => {
85
+ if (middleCount >= 12) return 3
86
+ if (middleCount >= 6) return 2
87
+ return 1
88
+ }
89
+
90
+ const FILL_ORDERS: Record<ColumnCount, [number[], number[]]> = {
91
+ 1: [[0], [0]],
92
+ 2: [[1, 0], [0, 1]],
93
+ 3: [[1, 0, 2], [1, 2, 0]],
94
+ }
95
+
96
+ const fillOrderForRow = (colCount: ColumnCount, row: number): number[] =>
97
+ FILL_ORDERS[colCount][row % 2]
98
+
99
+ const buildAdjacency = (links: { source: string, target: string }[]): { children: Adjacency, parents: Adjacency } => {
100
+ const children: Adjacency = new Map()
101
+ const parents: Adjacency = new Map()
102
+ for (const { source, target } of links) {
103
+ const kids = children.get(source) ?? []
104
+ kids.push(target)
105
+ children.set(source, kids)
106
+ const pars = parents.get(target) ?? []
107
+ pars.push(source)
108
+ parents.set(target, pars)
109
+ }
110
+ return { children, parents }
111
+ }
112
+
113
+ /** BFS from start nodes, yielding middle-node ids in visit order. */
114
+ const bfsMiddleOrder = (startIds: string[], middleIds: Set<string>, children: Adjacency): string[] => {
115
+ const visited = new Set<string>(startIds)
116
+ const order: string[] = []
117
+ const queue = [...startIds]
118
+ while (queue.length) {
119
+ const current = queue.shift()!
120
+ for (const child of children.get(current) ?? []) {
121
+ if (visited.has(child)) continue
122
+ visited.add(child)
123
+ if (middleIds.has(child)) order.push(child)
124
+ queue.push(child)
125
+ }
126
+ }
127
+ return order
128
+ }
129
+
130
+ const requiredRowFor = (nodeId: string, parents: Adjacency, rowOf: Map<string, number>): number => {
131
+ let required = 0
132
+ for (const pid of parents.get(nodeId) ?? []) {
133
+ const pr = rowOf.get(pid)
134
+ if (pr !== undefined && pr + 1 > required) required = pr + 1
135
+ }
136
+ return required
137
+ }
138
+
139
+ const findFreeSlot = (
140
+ fromRow: number,
141
+ colCount: ColumnCount,
142
+ taken: Set<string>,
143
+ ): GridSlot => {
144
+ // Upper bound: in the worst case every already-taken slot forces us to the
145
+ // next row. `taken.size` rows is always enough to find a fresh one since we
146
+ // place at most one node per call. +2 keeps the bound loose for safety.
147
+ const maxRows = taken.size + 2
148
+ for (let row = fromRow; row < fromRow + maxRows; row++) {
149
+ for (const col of fillOrderForRow(colCount, row)) {
150
+ if (!taken.has(`${row}:${col}`)) return { row, col }
151
+ }
152
+ }
153
+ throw new Error(`findFreeSlot: no free slot found within ${maxRows} rows from ${fromRow}`)
154
+ }
155
+
156
+ /** Assign (row, col) slots to each middle node in BFS order. */
157
+ const assignSlots = (bfsOrder: string[], parents: Adjacency, colCount: ColumnCount): Map<string, GridSlot> => {
158
+ const slotOf = new Map<string, GridSlot>()
159
+ const taken = new Set<string>()
160
+ const rowOf = new Map<string, number>()
161
+ for (const nodeId of bfsOrder) {
162
+ const slot = findFreeSlot(requiredRowFor(nodeId, parents, rowOf), colCount, taken)
163
+ slotOf.set(nodeId, slot)
164
+ rowOf.set(nodeId, slot.row)
165
+ taken.add(`${slot.row}:${slot.col}`)
166
+ }
167
+ return slotOf
168
+ }
169
+
170
+ /** Column index → horizontal pixel offset. Column 1 (center in 3-col) is at x=0. */
171
+ const columnX = (colCount: ColumnCount, col: number): number => {
172
+ if (colCount === 1) return 0
173
+ if (colCount === 2) return (col - 0.5) * COL_PITCH
174
+ return (col - 1) * COL_PITCH
175
+ }
176
+
177
+ /** Distribute `total` nodes horizontally around x=0. */
178
+ const centeredGroupX = (index: number, total: number): number =>
179
+ (index - (total - 1) / 2) * COL_PITCH
180
+
181
+ /**
182
+ * Custom layout algorithm:
183
+ * - Start and stop nodes are centered as groups on their own rows; their x
184
+ * positions are independent of the column grid.
185
+ * - Middle nodes fill 1/2/3 columns depending on middle-node count
186
+ * (<6 → 1 col, 6–11 → 2, 12+ → 3).
187
+ * - Processing order: BFS from start nodes.
188
+ * - Each node's row = min row such that all its already-placed parents have
189
+ * lower rows (cycles back to earlier rows are ignored).
190
+ * - Column fill order per row: center first, then alternate sides by row parity.
191
+ * - If a row has no free columns at the required row, bump to the next row.
192
+ */
193
+ const layout = computed(() => {
194
+ const { nodes: graphNodes, links } = props.graphData
195
+
196
+ const startNodes = graphNodes.filter(n => n.type === 'start')
197
+ const stopNodes = graphNodes.filter(n => n.type === 'stop')
198
+ const middleNodes = graphNodes.filter(n => n.type === 'step')
199
+ const middleIds = new Set(middleNodes.map(n => n.id))
200
+ const colCount = chooseColumnCount(middleNodes.length)
201
+
202
+ const { children, parents } = buildAdjacency(links)
203
+
204
+ const bfsOrder = bfsMiddleOrder(startNodes.map(n => n.id), middleIds, children)
205
+ // Include any middle nodes unreachable from start (defensive).
206
+ for (const n of middleNodes) {
207
+ if (!bfsOrder.includes(n.id)) bfsOrder.push(n.id)
208
+ }
209
+
210
+ const slotOf = assignSlots(bfsOrder, parents, colCount)
211
+
212
+ const layoutMap = new Map<string, { x: number, y: number }>()
213
+ startNodes.forEach((node, i) => {
214
+ layoutMap.set(node.id, { x: centeredGroupX(i, startNodes.length), y: 0 })
215
+ })
216
+ let maxRow = -1
217
+ middleNodes.forEach((node) => {
218
+ const { row, col } = slotOf.get(node.id)!
219
+ if (row > maxRow) maxRow = row
220
+ layoutMap.set(node.id, { x: columnX(colCount, col), y: (row + 1) * ROW_PITCH })
221
+ })
222
+ const stopRow = maxRow + 2
223
+ stopNodes.forEach((node, i) => {
224
+ layoutMap.set(node.id, { x: centeredGroupX(i, stopNodes.length), y: stopRow * ROW_PITCH })
225
+ })
226
+ return layoutMap
227
+ })
228
+
229
+ const nodes = computed(() => props.graphData.nodes.map((node) => {
230
+ const pos = layout.value.get(node.id)!
231
+ return {
232
+ id: node.id,
233
+ type: node.type,
234
+ position: pos,
235
+ data: node,
236
+ sourcePosition: Position.Bottom,
237
+ targetPosition: Position.Top,
238
+ }
239
+ }))
240
+
241
+ const edges = computed(() => props.graphData.links.map(link => ({
242
+ id: `${link.source}->${link.target}`,
243
+ source: link.source,
244
+ target: link.target,
245
+ animated: true,
246
+ markerEnd: { type: MarkerType.ArrowClosed, width: 24, height: 24 },
247
+ })))
248
+ </script>
249
+
250
+ <style scoped>
251
+ /* Selected nodes: bolder red border + red tint so even start/end nodes
252
+ * (already red) stand out clearly. Scoped + :deep keeps these rules from
253
+ * leaking into any sibling component that also uses vue-flow. */
254
+ :deep(.vue-flow__node.selected > *) {
255
+ border-color: rgb(239 68 68) !important; /* red-500 */
256
+ background-color: oklch(88.5% 0.062 18.334) !important; /* red-100 */
257
+ }
258
+ :deep(.dark .vue-flow__node.selected > *) {
259
+ background-color: oklch(25.8% 0.092 26.042) !important;
260
+ }
261
+ :deep(.vue-flow__edge.selected .vue-flow__edge-path) {
262
+ stroke: rgb(239 68 68) !important;
263
+ stroke-width: 2 !important;
264
+ }
265
+ </style>
@@ -0,0 +1,9 @@
1
+ <template>
2
+ <div class="py-5">
3
+ <MDCSlot unwrap="p" />
4
+ </div>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+
9
+ </script>
@@ -0,0 +1,9 @@
1
+ <template>
2
+ <div class="py-5">
3
+ <MDCSlot unwrap="p" />
4
+ </div>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+
9
+ </script>
@@ -0,0 +1,58 @@
1
+ <template>
2
+ <div>
3
+ <img
4
+ :src="imageUrl"
5
+ :alt="alt"
6
+ :width="width"
7
+ :height="height"
8
+ >
9
+ <p
10
+ v-if="alt"
11
+ class="text-[10px] italic leading-3 text-surface-500"
12
+ >
13
+ {{ alt }}
14
+ </p>
15
+ </div>
16
+ </template>
17
+
18
+ <script setup lang="ts">
19
+ import { getFileUrl } from '@core/sdk/client'
20
+
21
+ const props = defineProps<{
22
+ src: string
23
+ alt?: string
24
+ width?: string | number
25
+ height?: string | number
26
+ }>()
27
+
28
+ const { tenantId } = useTenant()
29
+ const imageUrl = ref<string | null>(props.src)
30
+
31
+ const fetchAndSetImageUrl = async () => {
32
+ if (props.src.startsWith('http')) {
33
+ return props.src
34
+ }
35
+ if (!tenantId.value) return
36
+
37
+ let src = props.src
38
+ if (src.includes('://')) {
39
+ src = src.split('://')[1]
40
+ }
41
+ const parts = src.split('/')
42
+ const [container, file_path] = [parts[0], parts.slice(1).join('/')]
43
+
44
+ const { url } = await getFileUrl({
45
+ composable: '$fetch',
46
+ path: {
47
+ tenant_id: tenantId.value!,
48
+ container,
49
+ file_path,
50
+ },
51
+ })
52
+ imageUrl.value = url
53
+ }
54
+
55
+ onMounted(() => {
56
+ fetchAndSetImageUrl()
57
+ })
58
+ </script>
@@ -0,0 +1,27 @@
1
+ import { type AgentClassDtoReadable, getAgentClass } from '@core/sdk/client'
2
+ import { minutesToMilliseconds } from 'date-fns'
3
+ import { useRoute } from 'vue-router'
4
+
5
+ export const useAgentClass = defineQuery(() => {
6
+ const route = useRoute()
7
+ const { tenantId } = useTenant()
8
+
9
+ const { data: agentClass, isPending: agentClassIsLoading } = useQuery<AgentClassDtoReadable>({
10
+ key: () => ['tenant', tenantId.value, 'agent-classes', route.params.agent_class as string],
11
+ staleTime: minutesToMilliseconds(5),
12
+ enabled: useTenantReady('agent_class'),
13
+ query: async () => {
14
+ return await getAgentClass({
15
+ composable: '$fetch',
16
+ path: {
17
+ tenant_id: tenantId.value!,
18
+ agent_class: route.params.agent_class as string,
19
+ },
20
+ })
21
+ },
22
+ })
23
+ return {
24
+ agentClass,
25
+ agentClassIsLoading,
26
+ }
27
+ })
@@ -0,0 +1,27 @@
1
+ import { type FullAgentInstanceDto, getAgentClassInstances } from '@core/sdk/client'
2
+ import { minutesToMilliseconds } from 'date-fns'
3
+ import { useRoute } from 'vue-router'
4
+
5
+ export const useAgentClassInstances = defineQuery(() => {
6
+ const route = useRoute()
7
+ const { tenantId } = useTenant()
8
+
9
+ const { data: agentClassInstances, isPending: agentClassInstancesAreLoading } = useQuery<FullAgentInstanceDto[]>({
10
+ key: () => ['tenant', tenantId.value, 'agent-class-instances', route.params.agent_class as string],
11
+ staleTime: minutesToMilliseconds(5),
12
+ enabled: useTenantReady('agent_class'),
13
+ query: async () => {
14
+ return await getAgentClassInstances({
15
+ composable: '$fetch',
16
+ path: {
17
+ tenant_id: tenantId.value!,
18
+ agent_class: route.params.agent_class as string,
19
+ },
20
+ })
21
+ },
22
+ })
23
+ return {
24
+ agentClassInstances,
25
+ agentClassInstancesAreLoading,
26
+ }
27
+ })
@@ -0,0 +1,27 @@
1
+ import { type AgentClassDtoReadable, getAgentClasses } from '@core/sdk/client'
2
+ import { minutesToMilliseconds } from 'date-fns'
3
+
4
+ export type AgentClassDto = AgentClassDtoReadable
5
+
6
+ export const useAgentClasses = defineQuery((options?: { online?: boolean }) => {
7
+ const { tenantId } = useTenant()
8
+
9
+ const { data: agentClasses, isPending: agentClassesAreLoading } = useQuery<AgentClassDto[]>({
10
+ key: () => ['tenant', tenantId.value, 'agent-classes', options?.online],
11
+ staleTime: minutesToMilliseconds(5),
12
+ enabled: useTenantReady(),
13
+ query: async () => {
14
+ return await getAgentClasses({
15
+ composable: '$fetch',
16
+ path: { tenant_id: tenantId.value! },
17
+ query: {
18
+ online: options?.online,
19
+ },
20
+ })
21
+ },
22
+ })
23
+ return {
24
+ agentClasses,
25
+ agentClassesAreLoading,
26
+ }
27
+ })
@@ -0,0 +1,8 @@
1
+ import type { MinimalAgentInstanceDto, ThreadDto, ContextualizedAgentEvent } from '@core/sdk/client'
2
+
3
+ export default (event: ContextualizedAgentEvent, thread: ThreadDto) => {
4
+ return computed<string | undefined>(() => thread.participating_agents
5
+ ?.find((agent: MinimalAgentInstanceDto) => agent.agent_id == event.agent_id && agent.agent_class == event.agent_class)
6
+ ?.agent_config?.icon,
7
+ )
8
+ }
@@ -0,0 +1,28 @@
1
+ import { type FullAgentInstanceDto, getAgentInstance } from '@core/sdk/client'
2
+ import { minutesToMilliseconds } from 'date-fns'
3
+ import { useRoute } from 'vue-router'
4
+
5
+ export const useAgentInstance = defineQuery(() => {
6
+ const route = useRoute()
7
+ const { tenantId } = useTenant()
8
+
9
+ const { data: agentInstance, isPending: agentInstanceIsLoading } = useQuery<FullAgentInstanceDto>({
10
+ key: () => ['tenant', tenantId.value, 'agent-instances', route.params.agent_class as string, route.params.agent_id as string],
11
+ staleTime: minutesToMilliseconds(5),
12
+ enabled: useTenantReady('agent_id', 'agent_class'),
13
+ query: async () => {
14
+ return await getAgentInstance({
15
+ composable: '$fetch',
16
+ path: {
17
+ tenant_id: tenantId.value!,
18
+ agent_id: route.params.agent_id as string,
19
+ agent_class: route.params.agent_class as string,
20
+ },
21
+ })
22
+ },
23
+ })
24
+ return {
25
+ agentInstance,
26
+ agentInstanceIsLoading,
27
+ }
28
+ })
@@ -0,0 +1,76 @@
1
+ import { getAgentInstanceThreads } from '@core/sdk/client'
2
+ import { ref, computed } from 'vue'
3
+ import { useRoute } from 'vue-router'
4
+
5
+ export const useAgentInstanceThreads = defineQuery(() => {
6
+ const route = useRoute()
7
+ const { tenantId } = useTenant()
8
+
9
+ // Pagination state
10
+ const currentPage = ref(1)
11
+ const pageSize = ref(10)
12
+
13
+ // Query to fetch paginated threads
14
+ const threadQuery = useQuery({
15
+ key: () => [
16
+ 'tenant',
17
+ tenantId.value,
18
+ 'agent-instance-threads',
19
+ route.params.agent_id as string,
20
+ route.params.agent_class as string,
21
+ currentPage.value,
22
+ pageSize.value,
23
+ ],
24
+ enabled: useTenantReady('agent_id', 'agent_class'),
25
+ query: async () => {
26
+ return await getAgentInstanceThreads({
27
+ composable: '$fetch',
28
+ path: {
29
+ tenant_id: tenantId.value!,
30
+ agent_id: route.params.agent_id as string,
31
+ agent_class: route.params.agent_class as string,
32
+ },
33
+ query: {
34
+ page: currentPage.value,
35
+ page_size: pageSize.value,
36
+ },
37
+ })
38
+ },
39
+ placeholderData: previousData => previousData, // Keep previous data while fetching
40
+ })
41
+
42
+ // Update page size and refetch
43
+ const setPageSize = (newSize: number) => {
44
+ pageSize.value = newSize
45
+ // When changing page size, reset to first page to avoid out-of-range issues
46
+ currentPage.value = 1
47
+ }
48
+
49
+ // Update current page and refetch
50
+ const setPage = (newPage: number) => {
51
+ currentPage.value = newPage
52
+ }
53
+
54
+ // Extract pagination metadata
55
+ const paginationMeta = computed(() => {
56
+ const data = threadQuery.state.value?.data
57
+
58
+ return {
59
+ total: data?.total ?? 0,
60
+ currentPage: data?.page ?? 1,
61
+ pageSize: data?.page_size ?? 10,
62
+ totalPages: data?.total_pages ?? 1,
63
+ }
64
+ })
65
+
66
+ return {
67
+ threads: computed(() => threadQuery.state.value?.data?.threads ?? []),
68
+ isLoading: computed(() => threadQuery.asyncStatus.value === 'loading'),
69
+ pagination: paginationMeta,
70
+ currentPage,
71
+ pageSize,
72
+ setPage,
73
+ setPageSize,
74
+ refetch: threadQuery.refetch,
75
+ }
76
+ })
@@ -0,0 +1,25 @@
1
+ import { type FullAgentInstanceDto, getAllAgentInstances } from '@core/sdk/client'
2
+ import { minutesToMilliseconds } from 'date-fns'
3
+
4
+ export const useAgentInstances = defineQuery((options?: { online?: boolean }) => {
5
+ const { tenantId } = useTenant()
6
+
7
+ const { data: agentInstances, isPending: agentInstancesAreLoading } = useQuery<FullAgentInstanceDto[]>({
8
+ key: () => ['tenant', tenantId.value, 'agent-instances', options?.online],
9
+ staleTime: minutesToMilliseconds(5),
10
+ enabled: useTenantReady(),
11
+ query: async () => {
12
+ return await getAllAgentInstances({
13
+ composable: '$fetch',
14
+ path: { tenant_id: tenantId.value! },
15
+ query: {
16
+ online: options?.online,
17
+ },
18
+ })
19
+ },
20
+ })
21
+ return {
22
+ agentInstances,
23
+ agentInstancesAreLoading,
24
+ }
25
+ })
@@ -0,0 +1,35 @@
1
+ import type { NavItem } from '@core/types/NavItem'
2
+
3
+ export function useAgentNavigation() {
4
+ const router = useRouter()
5
+ const route = useRoute()
6
+ const tenantPath = useTenantPath()
7
+ const { t } = useI18n()
8
+
9
+ const navItems = computed<NavItem[]>(() => [
10
+ {
11
+ name: t('agent.tabs.myAgents'),
12
+ key: 'agents',
13
+ path: '/service/agents',
14
+ isActive: () => route.path.startsWith(tenantPath('/service/agents')) && !route.path.includes('/service/agents/templates'),
15
+ },
16
+ {
17
+ name: t('agent.tabs.templates'),
18
+ key: 'templates',
19
+ path: '/service/agents/templates',
20
+ isActive: () => route.path.includes('/service/agents/templates'),
21
+ },
22
+ ])
23
+
24
+ const activeNavItem = computed<NavItem | undefined>(() => {
25
+ return navItems.value.find((navItem: NavItem) => navItem.isActive())
26
+ })
27
+
28
+ const toNavItem = (navItem: NavItem | null) => {
29
+ if (navItem) {
30
+ router.push(tenantPath(navItem.path))
31
+ }
32
+ }
33
+
34
+ return { navItems, activeNavItem, toNavItem }
35
+ }
@@ -0,0 +1,33 @@
1
+ import { createAgentInstance, type CreateAgentInstanceRequest } from '@core/sdk/client'
2
+
3
+ export const useCreateAgentInstance = defineMutation(() => {
4
+ const queryCache = useQueryCache()
5
+
6
+ const {
7
+ mutateAsync: createAgentInstanceMutation,
8
+ isPending: isCreating,
9
+ error: createError,
10
+ } = useMutation({
11
+ mutation: async ({ agentClass, request, tenantId }: { agentClass: string, request: CreateAgentInstanceRequest, tenantId: string }) => {
12
+ const result = await createAgentInstance({
13
+ composable: '$fetch',
14
+ path: {
15
+ tenant_id: tenantId,
16
+ agent_class: agentClass,
17
+ },
18
+ body: request,
19
+ })
20
+
21
+ // Invalidate agent instances cache to refresh the list
22
+ queryCache.invalidateQueries({ key: ['tenant', tenantId, 'agent-instances'] })
23
+ queryCache.invalidateQueries({ key: ['tenant', tenantId, 'agent-class-instances', agentClass] })
24
+ return result
25
+ },
26
+ })
27
+
28
+ return {
29
+ createAgentInstance: createAgentInstanceMutation,
30
+ isCreating,
31
+ createError,
32
+ }
33
+ })
@@ -0,0 +1,31 @@
1
+ import { deleteAgentInstance } from '@core/sdk/client'
2
+
3
+ export const useDeleteAgentInstance = defineMutation(() => {
4
+ const queryCache = useQueryCache()
5
+
6
+ const {
7
+ mutateAsync: deleteAgentInstanceMutation,
8
+ isPending: isDeleting,
9
+ error: deleteError,
10
+ } = useMutation({
11
+ mutation: async ({ agentClass, agentId, tenantId }: { agentClass: string, agentId: string, tenantId: string }) => {
12
+ await deleteAgentInstance({
13
+ composable: '$fetch',
14
+ path: {
15
+ tenant_id: tenantId,
16
+ agent_class: agentClass,
17
+ agent_id: agentId,
18
+ },
19
+ })
20
+
21
+ queryCache.invalidateQueries({ key: ['tenant', tenantId, 'agent-instances'] })
22
+ queryCache.invalidateQueries({ key: ['tenant', tenantId, 'agent-class-instances', agentClass] })
23
+ },
24
+ })
25
+
26
+ return {
27
+ deleteAgentInstance: deleteAgentInstanceMutation,
28
+ isDeleting,
29
+ deleteError,
30
+ }
31
+ })