@eventcatalog/core 3.40.2 → 3.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/dist/__mocks__/astro-content.d.cts +1 -1
  2. package/dist/__mocks__/astro-content.d.ts +1 -1
  3. package/dist/analytics/analytics.cjs +1 -1
  4. package/dist/analytics/analytics.js +2 -2
  5. package/dist/analytics/count-resources.cjs +1 -0
  6. package/dist/analytics/count-resources.js +1 -1
  7. package/dist/analytics/log-build.cjs +3 -1
  8. package/dist/analytics/log-build.js +4 -4
  9. package/dist/catalog-to-astro-content-directory.cjs +1 -0
  10. package/dist/catalog-to-astro-content-directory.js +2 -2
  11. package/dist/{chunk-4UVFXLPI.js → chunk-3DVHEVHQ.js} +1 -0
  12. package/dist/{chunk-K3ZVEX2Y.js → chunk-3H2RT3CM.js} +1 -1
  13. package/dist/{chunk-B7LKNRMT.js → chunk-3R6TKNHG.js} +1 -1
  14. package/dist/{chunk-D6UVZABG.js → chunk-DKFIEB24.js} +1 -1
  15. package/dist/{chunk-55D645EH.js → chunk-IR4IAKWS.js} +1 -0
  16. package/dist/{chunk-YDXB3BD2.js → chunk-O6KT4DPL.js} +1 -1
  17. package/dist/{chunk-D6IBLY3O.js → chunk-QMORF42U.js} +1 -0
  18. package/dist/{chunk-HSSCHCQA.js → chunk-QVJGIQYP.js} +1 -1
  19. package/dist/{chunk-PWIB7GLR.js → chunk-TWFS6THS.js} +1 -1
  20. package/dist/{chunk-5FFRK3S5.js → chunk-ZN3JKTWB.js} +3 -2
  21. package/dist/constants.cjs +1 -1
  22. package/dist/constants.js +1 -1
  23. package/dist/eventcatalog.cjs +5 -1
  24. package/dist/eventcatalog.config.d.cts +4 -0
  25. package/dist/eventcatalog.config.d.ts +4 -0
  26. package/dist/eventcatalog.js +10 -10
  27. package/dist/generate.cjs +1 -1
  28. package/dist/generate.js +3 -3
  29. package/dist/map-catalog-to-astro.cjs +1 -0
  30. package/dist/map-catalog-to-astro.js +1 -1
  31. package/dist/search-indexer.cjs +1 -0
  32. package/dist/search-indexer.js +1 -1
  33. package/dist/utils/cli-logger.cjs +1 -1
  34. package/dist/utils/cli-logger.js +2 -2
  35. package/dist/watcher.cjs +1 -0
  36. package/dist/watcher.js +2 -2
  37. package/eventcatalog/public/agents/anthropic-dark.svg +1 -0
  38. package/eventcatalog/public/agents/anthropic-light.svg +1 -0
  39. package/eventcatalog/public/agents/openai-dark.svg +1 -0
  40. package/eventcatalog/public/agents/openai-light.svg +1 -0
  41. package/eventcatalog/public/agents/openai.svg +1 -0
  42. package/eventcatalog/public/icons/agent/anthropic-dark.svg +1 -0
  43. package/eventcatalog/public/icons/agent/anthropic-light.svg +1 -0
  44. package/eventcatalog/public/icons/agent/anthropic.svg +1 -0
  45. package/eventcatalog/public/icons/agent/gemini.svg +1 -0
  46. package/eventcatalog/public/icons/agent/openai-dark.svg +1 -0
  47. package/eventcatalog/public/icons/agent/openai-light.svg +1 -0
  48. package/eventcatalog/public/icons/agent/openai.svg +1 -0
  49. package/eventcatalog/public/icons/agents/anthropic-dark.svg +1 -0
  50. package/eventcatalog/public/icons/agents/anthropic-light.svg +1 -0
  51. package/eventcatalog/public/icons/agents/anthropic.svg +1 -0
  52. package/eventcatalog/public/icons/agents/gemini.svg +1 -0
  53. package/eventcatalog/public/icons/agents/openai-dark.svg +1 -0
  54. package/eventcatalog/public/icons/agents/openai-light.svg +1 -0
  55. package/eventcatalog/public/icons/agents/openai.svg +1 -0
  56. package/eventcatalog/public/icons/protocols/mcp-dark.svg +1 -0
  57. package/eventcatalog/public/icons/protocols/mcp-light.svg +1 -0
  58. package/eventcatalog/public/icons/protocols/mcp.svg +1 -0
  59. package/eventcatalog/public/icons/tools/datadog.svg +1 -0
  60. package/eventcatalog/public/icons/tools/github.svg +1 -0
  61. package/eventcatalog/public/icons/tools/hubspot.svg +1 -0
  62. package/eventcatalog/public/icons/tools/slack.svg +1 -0
  63. package/eventcatalog/public/icons/tools/snowflake.svg +1 -0
  64. package/eventcatalog/public/icons/tools/zendesk.svg +1 -0
  65. package/eventcatalog/src/components/Badge.astro +41 -2
  66. package/eventcatalog/src/components/Grids/MessageGrid.tsx +16 -11
  67. package/eventcatalog/src/components/MDX/AgentTools/AgentTools.astro +132 -0
  68. package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +2 -0
  69. package/eventcatalog/src/components/MDX/ResourceRef/ResourceRef.astro +8 -3
  70. package/eventcatalog/src/components/MDX/components.tsx +2 -0
  71. package/eventcatalog/src/components/Search/SearchModal.tsx +3 -0
  72. package/eventcatalog/src/components/Search/search-utils.ts +2 -0
  73. package/eventcatalog/src/components/SideNav/NestedSideBar/SearchBar.tsx +3 -0
  74. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +3 -0
  75. package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +165 -0
  76. package/eventcatalog/src/components/Tables/Discover/columns.tsx +132 -7
  77. package/eventcatalog/src/components/Tables/Table.tsx +2 -0
  78. package/eventcatalog/src/components/Tables/columns/TeamsTableColumns.tsx +17 -0
  79. package/eventcatalog/src/components/Tables/columns/UserTableColumns.tsx +17 -0
  80. package/eventcatalog/src/content.config.ts +83 -25
  81. package/eventcatalog/src/enterprise/collections/resource-docs-utils.ts +7 -4
  82. package/eventcatalog/src/enterprise/mcp/mcp-server.ts +9 -2
  83. package/eventcatalog/src/enterprise/tools/catalog-tools.ts +62 -28
  84. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +13 -1
  85. package/eventcatalog/src/pages/_index.astro +1 -3
  86. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +5 -5
  87. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +5 -2
  88. package/eventcatalog/src/pages/directory/[type]/index.astro +2 -0
  89. package/eventcatalog/src/pages/discover/[type]/_index.data.ts +5 -0
  90. package/eventcatalog/src/pages/discover/[type]/index.astro +69 -23
  91. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId].mdx.ts +1 -0
  92. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +1 -0
  93. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +1 -1
  94. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +47 -2
  95. package/eventcatalog/src/pages/docs/[type]/[id]/[version].md.ts +2 -0
  96. package/eventcatalog/src/pages/docs/[type]/[id]/[version].mdx.ts +2 -0
  97. package/eventcatalog/src/pages/docs/[type]/[id]/_index.data.ts +1 -0
  98. package/eventcatalog/src/pages/docs/llm/llms-full.txt.ts +3 -0
  99. package/eventcatalog/src/pages/docs/llm/llms.txt.ts +3 -0
  100. package/eventcatalog/src/pages/docs/teams/[id]/index.astro +24 -1
  101. package/eventcatalog/src/pages/docs/users/[id]/index.astro +24 -1
  102. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +2 -1
  103. package/eventcatalog/src/stores/sidebar-store/builders/agent.ts +141 -0
  104. package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +9 -0
  105. package/eventcatalog/src/stores/sidebar-store/builders/flow.ts +19 -0
  106. package/eventcatalog/src/stores/sidebar-store/builders/message.ts +8 -2
  107. package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +10 -7
  108. package/eventcatalog/src/stores/sidebar-store/state.ts +121 -2
  109. package/eventcatalog/src/types/index.ts +3 -1
  110. package/eventcatalog/src/utils/collection-colors.ts +5 -0
  111. package/eventcatalog/src/utils/collections/agents.ts +163 -0
  112. package/eventcatalog/src/utils/collections/commands.ts +3 -2
  113. package/eventcatalog/src/utils/collections/domains.ts +94 -15
  114. package/eventcatalog/src/utils/collections/events.ts +3 -2
  115. package/eventcatalog/src/utils/collections/flows.ts +20 -3
  116. package/eventcatalog/src/utils/collections/icons.ts +3 -1
  117. package/eventcatalog/src/utils/collections/messages.ts +35 -5
  118. package/eventcatalog/src/utils/collections/queries.ts +3 -2
  119. package/eventcatalog/src/utils/collections/schemas.ts +4 -4
  120. package/eventcatalog/src/utils/collections/services.ts +1 -1
  121. package/eventcatalog/src/utils/collections/teams.ts +5 -1
  122. package/eventcatalog/src/utils/collections/types.ts +1 -0
  123. package/eventcatalog/src/utils/collections/users.ts +5 -1
  124. package/eventcatalog/src/utils/collections/util.ts +2 -0
  125. package/eventcatalog/src/utils/eventcatalog-config/catalog.ts +1 -0
  126. package/eventcatalog/src/utils/llms.ts +1 -1
  127. package/eventcatalog/src/utils/node-graphs/agents-node-graph.ts +4 -0
  128. package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +2 -2
  129. package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +42 -9
  130. package/eventcatalog/src/utils/node-graphs/export-mermaid.ts +20 -0
  131. package/eventcatalog/src/utils/node-graphs/export-node-graph.ts +4 -0
  132. package/eventcatalog/src/utils/node-graphs/flows-node-graph.ts +22 -1
  133. package/eventcatalog/src/utils/node-graphs/message-node-graph.ts +175 -98
  134. package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +117 -23
  135. package/eventcatalog/src/utils/node-graphs/utils/utils.ts +30 -0
  136. package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +2 -0
  137. package/eventcatalog/src/utils/resource-reference-colors.ts +1 -0
  138. package/package.json +4 -4
@@ -15,8 +15,9 @@ export const getTeams = async (): Promise<Team[]> => {
15
15
  }
16
16
 
17
17
  // 1. Fetch all collections in parallel
18
- const [allTeams, allDomains, allServices, allEvents, allCommands, allQueries] = await Promise.all([
18
+ const [allTeams, allAgents, allDomains, allServices, allEvents, allCommands, allQueries] = await Promise.all([
19
19
  getCollection('teams'),
20
+ getCollection('agents'),
20
21
  getCollection('domains'),
21
22
  getCollection('services'),
22
23
  getCollection('events'),
@@ -45,6 +46,7 @@ export const getTeams = async (): Promise<Team[]> => {
45
46
  }
46
47
  };
47
48
 
49
+ addToIndex(allAgents);
48
50
  addToIndex(allDomains);
49
51
  addToIndex(allServices);
50
52
  addToIndex(allEvents);
@@ -57,6 +59,7 @@ export const getTeams = async (): Promise<Team[]> => {
57
59
  const ownedItems = ownershipMap.get(teamId) || [];
58
60
 
59
61
  // Categorize items
62
+ const ownedAgents = ownedItems.filter((i) => i.collection === 'agents') as CollectionEntry<'agents'>[];
60
63
  const ownedDomains = ownedItems.filter((i) => i.collection === 'domains') as CollectionEntry<'domains'>[];
61
64
  const ownedServices = ownedItems.filter((i) => i.collection === 'services') as CollectionEntry<'services'>[];
62
65
  const ownedEvents = ownedItems.filter((i) => i.collection === 'events') as CollectionEntry<'events'>[];
@@ -67,6 +70,7 @@ export const getTeams = async (): Promise<Team[]> => {
67
70
  ...team,
68
71
  data: {
69
72
  ...team.data,
73
+ ownedAgents,
70
74
  ownedDomains,
71
75
  ownedServices,
72
76
  ownedCommands,
@@ -2,5 +2,6 @@ import type { CollectionEntry } from 'astro:content';
2
2
 
3
3
  // Shared types to avoid circular dependencies between domains.ts and services.ts
4
4
  export type Service = CollectionEntry<'services'>;
5
+ export type Agent = CollectionEntry<'agents'>;
5
6
  export type Domain = CollectionEntry<'domains'>;
6
7
  export type UbiquitousLanguage = CollectionEntry<'ubiquitousLanguages'>;
@@ -16,8 +16,9 @@ export const getUsers = async (): Promise<User[]> => {
16
16
  }
17
17
 
18
18
  // 1. Fetch all collections in parallel
19
- const [allUsers, allDomains, allServices, allEvents, allCommands, allQueries, allTeams] = await Promise.all([
19
+ const [allUsers, allAgents, allDomains, allServices, allEvents, allCommands, allQueries, allTeams] = await Promise.all([
20
20
  getCollection('users'),
21
+ getCollection('agents'),
21
22
  getCollection('domains'),
22
23
  getCollection('services'),
23
24
  getCollection('events'),
@@ -52,6 +53,7 @@ export const getUsers = async (): Promise<User[]> => {
52
53
  }
53
54
  };
54
55
 
56
+ addToIndex(allAgents);
55
57
  addToIndex(allDomains);
56
58
  addToIndex(allServices);
57
59
  addToIndex(allEvents);
@@ -84,6 +86,7 @@ export const getUsers = async (): Promise<User[]> => {
84
86
  const allOwnedItems = Array.from(new Set([...directOwnedItems, ...teamOwnedItems]));
85
87
 
86
88
  // Categorize items
89
+ const ownedAgents = allOwnedItems.filter((i) => i.collection === 'agents') as CollectionEntry<'agents'>[];
87
90
  const ownedDomains = allOwnedItems.filter((i) => i.collection === 'domains') as CollectionEntry<'domains'>[];
88
91
  const ownedServices = allOwnedItems.filter((i) => i.collection === 'services') as CollectionEntry<'services'>[];
89
92
  const ownedEvents = allOwnedItems.filter((i) => i.collection === 'events') as CollectionEntry<'events'>[];
@@ -94,6 +97,7 @@ export const getUsers = async (): Promise<User[]> => {
94
97
  ...user,
95
98
  data: {
96
99
  ...user.data,
100
+ ownedAgents,
97
101
  ownedDomains,
98
102
  ownedServices,
99
103
  ownedEvents,
@@ -173,6 +173,7 @@ export const findMatchingNodes = (
173
173
  };
174
174
 
175
175
  export const resourceToCollectionMap = {
176
+ agent: 'agents',
176
177
  service: 'services',
177
178
  event: 'events',
178
179
  command: 'commands',
@@ -189,6 +190,7 @@ export const resourceToCollectionMap = {
189
190
  } as const;
190
191
 
191
192
  export const collectionToResourceMap = {
193
+ agents: 'agent',
192
194
  services: 'service',
193
195
  events: 'event',
194
196
  commands: 'command',
@@ -10,6 +10,7 @@ const getConfigValue = (obj: any, key: string, defaultValue: any) => {
10
10
  export const isCollectionVisibleInCatalog = (collection: string) => {
11
11
  const sidebarConfig = config?.default?.docs?.sidebar || {};
12
12
  const collections = [
13
+ 'agents',
13
14
  'events',
14
15
  'commands',
15
16
  'queries',
@@ -5,7 +5,7 @@ import { join } from 'path';
5
5
  import fs from 'fs';
6
6
 
7
7
  export const addSchemaToMarkdown = (collection: CollectionEntry<CollectionTypes>, file: string) => {
8
- const resourceData = collection?.data;
8
+ const resourceData = collection?.data as any;
9
9
  const fileToResource = collection.filePath ?? '';
10
10
  let schemas: string[] = [];
11
11
 
@@ -0,0 +1,4 @@
1
+ import { getNodesAndEdges as getServiceLikeNodesAndEdges } from './services-node-graph';
2
+
3
+ export const getNodesAndEdges = (props: Parameters<typeof getServiceLikeNodesAndEdges>[0]) =>
4
+ getServiceLikeNodesAndEdges({ ...props, collection: 'agents' });
@@ -68,7 +68,7 @@ export const getNodesAndEdges = async ({ id, version, defaultFlow, mode = 'simpl
68
68
  contextMenu: buildContextMenuForService({
69
69
  id: service.data.id,
70
70
  version: service.data.version,
71
- specifications: service.data.specifications as { type: string; path: string }[],
71
+ specifications: (service.data as any).specifications as { type: string; path: string }[],
72
72
  repository: service.data.repository as { url: string },
73
73
  }),
74
74
  },
@@ -161,7 +161,7 @@ export const getNodesAndEdges = async ({ id, version, defaultFlow, mode = 'simpl
161
161
  contextMenu: buildContextMenuForService({
162
162
  id: service.data.id,
163
163
  version: service.data.version,
164
- specifications: service.data.specifications as { type: string; path: string }[],
164
+ specifications: (service.data as any).specifications as { type: string; path: string }[],
165
165
  repository: service.data.repository as { url: string },
166
166
  }),
167
167
  },
@@ -8,11 +8,13 @@ import {
8
8
  createEdge,
9
9
  } from '@utils/node-graphs/utils/utils';
10
10
  import { getNodesAndEdges as getServicesNodeAndEdges } from './services-node-graph';
11
+ import { getNodesAndEdges as getAgentsNodeAndEdges } from './agents-node-graph';
11
12
  import { getNodesAndEdges as getDataProductsNodeAndEdges } from './data-products-node-graph';
12
13
  import merge from 'lodash.merge';
13
14
  import { createVersionedMap, findInMap } from '@utils/collections/util';
14
15
  import type { Node } from '@xyflow/react';
15
16
  import { getProducersOfMessage } from '@utils/collections/services';
17
+ import { getProducersOfMessage as getAgentProducersOfMessage } from '@utils/collections/agents';
16
18
 
17
19
  type DagreGraph = any;
18
20
 
@@ -27,9 +29,10 @@ export const getNodesAndEdgesForDomainContextMap = async ({ defaultFlow = null }
27
29
  edges = [] as any;
28
30
 
29
31
  // 1. Parallel Fetching
30
- const [allDomains, services, events, commands, queries] = await Promise.all([
32
+ const [allDomains, services, agents, events, commands, queries] = await Promise.all([
31
33
  getCollection('domains'),
32
34
  getCollection('services'),
35
+ getCollection('agents'),
33
36
  getCollection('events'),
34
37
  getCollection('commands'),
35
38
  getCollection('queries'),
@@ -40,19 +43,23 @@ export const getNodesAndEdgesForDomainContextMap = async ({ defaultFlow = null }
40
43
 
41
44
  // 2. Build optimized maps
42
45
  const serviceMap = createVersionedMap(services);
46
+ const agentMap = createVersionedMap(agents);
43
47
  const messageMap = createVersionedMap(messages);
44
48
 
45
49
  domains.forEach((domain, index) => {
46
50
  const nodeId = generateIdForNode(domain);
47
51
  const rawServices = domain.data.services ?? [];
52
+ const rawAgents = domain.data.agents ?? [];
48
53
 
49
54
  // Optimized service resolution
50
55
  const domainServices = rawServices
51
56
  .map((service) => findInMap(serviceMap, service.id, service.version))
52
57
  .filter((e) => e !== undefined);
58
+ const domainAgents = rawAgents.map((agent) => findInMap(agentMap, agent.id, agent.version)).filter((e) => e !== undefined);
59
+ const domainResources = [...domainServices, ...domainAgents];
53
60
 
54
61
  // Calculate domain node size based on services
55
- const servicesCount = domainServices.length;
62
+ const servicesCount = domainResources.length;
56
63
  const SERVICES_PER_ROW = 1;
57
64
  const SERVICE_WIDTH = 330;
58
65
  const SERVICE_HEIGHT = 120;
@@ -109,8 +116,8 @@ export const getNodesAndEdgesForDomainContextMap = async ({ defaultFlow = null }
109
116
  } as Node);
110
117
 
111
118
  // Position services in a grid within the domain
112
- if (domainServices) {
113
- domainServices.forEach((service, serviceIndex) => {
119
+ if (domainResources) {
120
+ domainResources.forEach((service, serviceIndex) => {
114
121
  const row = Math.floor(serviceIndex / SERVICES_PER_ROW);
115
122
  const col = serviceIndex % SERVICES_PER_ROW;
116
123
 
@@ -123,7 +130,7 @@ export const getNodesAndEdgesForDomainContextMap = async ({ defaultFlow = null }
123
130
  id: generateIdForNode(service),
124
131
  sourcePosition: 'right',
125
132
  targetPosition: 'left',
126
- type: 'services',
133
+ type: service.collection,
127
134
  position: {
128
135
  x: xPosition,
129
136
  y: yPosition,
@@ -133,7 +140,7 @@ export const getNodesAndEdgesForDomainContextMap = async ({ defaultFlow = null }
133
140
  draggable: false,
134
141
  data: {
135
142
  mode: 'full',
136
- service,
143
+ ...(service.collection === 'agents' ? { agent: service.data } : { service: service.data }),
137
144
  },
138
145
  });
139
146
 
@@ -150,10 +157,12 @@ export const getNodesAndEdgesForDomainContextMap = async ({ defaultFlow = null }
150
157
  // Based on original code, it iterates `receives`.
151
158
 
152
159
  for (const receive of receives) {
153
- const producers = getProducersOfMessage(services, receive);
160
+ const producers = [...getAgentProducersOfMessage(agents, receive), ...getProducersOfMessage(services, receive)];
154
161
 
155
162
  for (const producer of producers) {
156
- const isSameDomain = domainServices.some((domainService) => domainService.data.id === producer.data.id);
163
+ const isSameDomain = domainResources.some(
164
+ (domainService) => domainService.collection === producer.collection && domainService.data.id === producer.data.id
165
+ );
157
166
 
158
167
  if (!isSameDomain) {
159
168
  edges.push(
@@ -200,9 +209,10 @@ export const getNodesAndEdges = async ({
200
209
  edges = new Map();
201
210
 
202
211
  // 1. Parallel Fetching
203
- const [domains, services, dataProducts] = await Promise.all([
212
+ const [domains, services, agents, dataProducts] = await Promise.all([
204
213
  getCollection('domains'),
205
214
  getCollection('services'),
215
+ getCollection('agents'),
206
216
  getCollection('data-products'),
207
217
  ]);
208
218
 
@@ -218,10 +228,12 @@ export const getNodesAndEdges = async ({
218
228
 
219
229
  // 2. Build optimized maps
220
230
  const serviceMap = createVersionedMap(services);
231
+ const agentMap = createVersionedMap(agents);
221
232
  const domainMap = createVersionedMap(domains);
222
233
  const dataProductMap = createVersionedMap(dataProducts);
223
234
 
224
235
  const rawServices = domain?.data.services || [];
236
+ const rawAgents = domain?.data.agents || [];
225
237
  const rawSubDomains = domain?.data.domains || [];
226
238
  const rawDataProducts = (domain?.data as any)['data-products'] || [];
227
239
 
@@ -231,6 +243,11 @@ export const getNodesAndEdges = async ({
231
243
  .filter((s): s is any => !!s)
232
244
  .map((svc) => ({ id: svc.data.id, version: svc.data.version }));
233
245
 
246
+ const domainAgentsWithVersion = rawAgents
247
+ .map((agent) => findInMap(agentMap, agent.id, agent.version))
248
+ .filter((a): a is any => !!a)
249
+ .map((agent) => ({ id: agent.data.id, version: agent.data.version }));
250
+
234
251
  const domainSubDomainsWithVersion = rawSubDomains
235
252
  .map((subDomain) => findInMap(domainMap, subDomain.id, subDomain.version))
236
253
  .filter((d): d is any => !!d)
@@ -267,6 +284,22 @@ export const getNodesAndEdges = async ({
267
284
  serviceEdges.forEach((e) => edges.set(e.id, e));
268
285
  }
269
286
 
287
+ for (const agent of domainAgentsWithVersion) {
288
+ const { nodes: agentNodes, edges: agentEdges } = await getAgentsNodeAndEdges({
289
+ id: agent.id,
290
+ version: agent.version,
291
+ defaultFlow: flow,
292
+ mode,
293
+ renderAllEdges: true,
294
+ channelRenderMode,
295
+ });
296
+ agentNodes.forEach((n) => {
297
+ nodes.set(n.id, nodes.has(n.id) ? merge(nodes.get(n.id), n) : n);
298
+ });
299
+ // @ts-ignore
300
+ agentEdges.forEach((e) => edges.set(e.id, e));
301
+ }
302
+
270
303
  for (const dataProduct of domainDataProductsWithVersion) {
271
304
  const { nodes: dataProductNodes, edges: dataProductEdges } = await getDataProductsNodeAndEdges({
272
305
  id: dataProduct.id,
@@ -17,6 +17,10 @@ export interface MermaidExportOptions {
17
17
  * Format: [prefix, suffix]
18
18
  */
19
19
  const NODE_SHAPE_MAP: Record<string, [string, string]> = {
20
+ agents: ['[[', ']]'],
21
+ agent: ['[[', ']]'],
22
+ agentTool: ['[', ']'],
23
+ 'agent-tool': ['[', ']'],
20
24
  services: ['[[', ']]'], // stadium shape
21
25
  service: ['[[', ']]'],
22
26
  events: ['>', ']'], // flag/asymmetric shape (message-like)
@@ -50,6 +54,10 @@ const NODE_SHAPE_MAP: Record<string, [string, string]> = {
50
54
  * Mermaid class definitions for styling different node types
51
55
  */
52
56
  const NODE_STYLE_CLASSES: Record<string, string> = {
57
+ agents: 'fill:#0ea5e9,stroke:#0369a1,color:#fff',
58
+ agent: 'fill:#0ea5e9,stroke:#0369a1,color:#fff',
59
+ agentTool: 'fill:#8b5cf6,stroke:#6d28d9,color:#fff',
60
+ 'agent-tool': 'fill:#8b5cf6,stroke:#6d28d9,color:#fff',
53
61
  services: 'fill:#ec4899,stroke:#be185d,color:#fff',
54
62
  service: 'fill:#ec4899,stroke:#be185d,color:#fff',
55
63
  events: 'fill:#f97316,stroke:#c2410c,color:#fff',
@@ -124,6 +132,18 @@ export function getNodeLabel(node: Node): string {
124
132
  if (!data) return node.id;
125
133
 
126
134
  // Handle different node types and their data structures
135
+ if (type === 'agents' || type === 'agent') {
136
+ const agent = (data as any).agent;
137
+ const name = agent?.name || agent?.id || node.id;
138
+ const version = agent?.data?.version || agent?.version;
139
+ return formatLabelWithVersion(name, version);
140
+ }
141
+
142
+ if (type === 'agentTool' || type === 'agent-tool') {
143
+ const agentTool = (data as any).agentTool;
144
+ return agentTool?.name || agentTool?.id || node.id;
145
+ }
146
+
127
147
  if (type === 'services' || type === 'service') {
128
148
  const service = (data as any).service;
129
149
  const name = service?.name || service?.id || node.id;
@@ -18,6 +18,8 @@ interface NodeDataWithResources {
18
18
  entity?: ResourceData;
19
19
  message?: ResourceData;
20
20
  flow?: ResourceData;
21
+ agent?: ResourceData;
22
+ agentTool?: ResourceData;
21
23
  service?: ResourceData;
22
24
  step?: ResourceData;
23
25
  user?: ResourceData;
@@ -32,6 +34,8 @@ export const exportNodeGraphForStudio = (data: ReactFlowJsonObject) => {
32
34
  'entity',
33
35
  'message',
34
36
  'flow',
37
+ 'agent',
38
+ 'agentTool',
35
39
  'service',
36
40
  'step',
37
41
  'user',
@@ -24,6 +24,7 @@ interface Props {
24
24
 
25
25
  interface Maps {
26
26
  messageMap: Map<string, any[]>;
27
+ agentMap: Map<string, any[]>;
27
28
  serviceMap: Map<string, any[]>;
28
29
  flowMap: Map<string, any[]>;
29
30
  containerMap: Map<string, any[]>;
@@ -39,6 +40,15 @@ const getServiceNode = (step: any, serviceMap: Map<string, any[]>) => {
39
40
  };
40
41
  };
41
42
 
43
+ const getAgentNode = (step: any, agentMap: Map<string, any[]>) => {
44
+ const agent = findInMap(agentMap, step.agent.id, step.agent.version);
45
+ return {
46
+ ...step,
47
+ type: agent ? agent.collection : 'step',
48
+ agent,
49
+ };
50
+ };
51
+
42
52
  const getFlowNode = (step: any, flowMap: Map<string, any[]>) => {
43
53
  const flow = findInMap(flowMap, step.flow.id, step.flow.version);
44
54
  return {
@@ -117,6 +127,7 @@ const buildFlowGraphInternal = (
117
127
  const stepNodeId = (stepId: any) => `step-${stepId}`;
118
128
 
119
129
  const hydratedSteps = steps.map((step: any) => {
130
+ if (step.agent) return getAgentNode(step, maps.agentMap);
120
131
  if (step.service) return getServiceNode(step, maps.serviceMap);
121
132
  if (step.flow) return getFlowNode(step, maps.flowMap);
122
133
  if (step.container) return getContainerNode(step, maps.containerMap);
@@ -143,6 +154,14 @@ const buildFlowGraphInternal = (
143
154
  type: step.type,
144
155
  } as NodeType;
145
156
 
157
+ if (step.agent) {
158
+ node.data.agent = { ...step.agent, ...step.agent.data };
159
+ node.data.contextMenu = buildContextMenuForResource({
160
+ collection: 'agents',
161
+ id: step.agent.data.id,
162
+ version: step.agent.data.version,
163
+ });
164
+ }
146
165
  if (step.service) {
147
166
  node.data.service = { ...step.service, ...step.service.data };
148
167
  node.data.contextMenu = buildContextMenuForService({
@@ -255,11 +274,12 @@ const buildFlowGraphInternal = (
255
274
  export const getNodesAndEdges = async ({ id, defaultFlow, version, mode = 'simple', renderAllEdges = false }: Props) => {
256
275
  const graph = defaultFlow || createDagreGraph({ ranksep: 360, nodesep: 200 });
257
276
 
258
- const [flows, events, commands, queries, services, containers, dataProducts] = await Promise.all([
277
+ const [flows, events, commands, queries, agents, services, containers, dataProducts] = await Promise.all([
259
278
  getCollection('flows'),
260
279
  getCollection('events'),
261
280
  getCollection('commands'),
262
281
  getCollection('queries'),
282
+ getCollection('agents'),
263
283
  getCollection('services'),
264
284
  getCollection('containers'),
265
285
  getCollection('data-products'),
@@ -277,6 +297,7 @@ export const getNodesAndEdges = async ({ id, defaultFlow, version, mode = 'simpl
277
297
  const messages = [...events, ...commands, ...queries];
278
298
  const maps: Maps = {
279
299
  messageMap: createVersionedMap(messages),
300
+ agentMap: createVersionedMap(agents),
280
301
  serviceMap: createVersionedMap(services),
281
302
  flowMap: createVersionedMap(flows),
282
303
  containerMap: createVersionedMap(containers),