@eventcatalog/core 3.40.1 → 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 (139) hide show
  1. package/bin/eventcatalog.config.d.ts +1 -0
  2. package/dist/__mocks__/astro-content.d.cts +1 -1
  3. package/dist/__mocks__/astro-content.d.ts +1 -1
  4. package/dist/analytics/analytics.cjs +1 -1
  5. package/dist/analytics/analytics.js +2 -2
  6. package/dist/analytics/count-resources.cjs +1 -0
  7. package/dist/analytics/count-resources.js +1 -1
  8. package/dist/analytics/log-build.cjs +3 -2
  9. package/dist/analytics/log-build.js +4 -4
  10. package/dist/catalog-to-astro-content-directory.cjs +1 -0
  11. package/dist/catalog-to-astro-content-directory.js +2 -2
  12. package/dist/{chunk-4UVFXLPI.js → chunk-3DVHEVHQ.js} +1 -0
  13. package/dist/{chunk-K3ZVEX2Y.js → chunk-3H2RT3CM.js} +1 -1
  14. package/dist/{chunk-BRMLU4PR.js → chunk-3R6TKNHG.js} +1 -1
  15. package/dist/{chunk-OIVICT4V.js → chunk-DKFIEB24.js} +1 -1
  16. package/dist/{chunk-55D645EH.js → chunk-IR4IAKWS.js} +1 -0
  17. package/dist/{chunk-YDXB3BD2.js → chunk-O6KT4DPL.js} +1 -1
  18. package/dist/{chunk-D6IBLY3O.js → chunk-QMORF42U.js} +1 -0
  19. package/dist/{chunk-HNG4KOYQ.js → chunk-QVJGIQYP.js} +1 -1
  20. package/dist/{chunk-4OEF5W6Y.js → chunk-TWFS6THS.js} +1 -1
  21. package/dist/{chunk-7UR72UMK.js → chunk-ZN3JKTWB.js} +5 -5
  22. package/dist/constants.cjs +1 -1
  23. package/dist/constants.js +1 -1
  24. package/dist/eventcatalog.cjs +5 -2
  25. package/dist/eventcatalog.config.d.cts +27 -11
  26. package/dist/eventcatalog.config.d.ts +27 -11
  27. package/dist/eventcatalog.js +14 -14
  28. package/dist/generate.cjs +1 -1
  29. package/dist/generate.js +3 -3
  30. package/dist/map-catalog-to-astro.cjs +1 -0
  31. package/dist/map-catalog-to-astro.js +1 -1
  32. package/dist/search-indexer.cjs +1 -0
  33. package/dist/search-indexer.js +1 -1
  34. package/dist/utils/cli-logger.cjs +1 -1
  35. package/dist/utils/cli-logger.js +2 -2
  36. package/dist/watcher.cjs +1 -0
  37. package/dist/watcher.js +2 -2
  38. package/eventcatalog/public/agents/anthropic-dark.svg +1 -0
  39. package/eventcatalog/public/agents/anthropic-light.svg +1 -0
  40. package/eventcatalog/public/agents/openai-dark.svg +1 -0
  41. package/eventcatalog/public/agents/openai-light.svg +1 -0
  42. package/eventcatalog/public/agents/openai.svg +1 -0
  43. package/eventcatalog/public/icons/agent/anthropic-dark.svg +1 -0
  44. package/eventcatalog/public/icons/agent/anthropic-light.svg +1 -0
  45. package/eventcatalog/public/icons/agent/anthropic.svg +1 -0
  46. package/eventcatalog/public/icons/agent/gemini.svg +1 -0
  47. package/eventcatalog/public/icons/agent/openai-dark.svg +1 -0
  48. package/eventcatalog/public/icons/agent/openai-light.svg +1 -0
  49. package/eventcatalog/public/icons/agent/openai.svg +1 -0
  50. package/eventcatalog/public/icons/agents/anthropic-dark.svg +1 -0
  51. package/eventcatalog/public/icons/agents/anthropic-light.svg +1 -0
  52. package/eventcatalog/public/icons/agents/anthropic.svg +1 -0
  53. package/eventcatalog/public/icons/agents/gemini.svg +1 -0
  54. package/eventcatalog/public/icons/agents/openai-dark.svg +1 -0
  55. package/eventcatalog/public/icons/agents/openai-light.svg +1 -0
  56. package/eventcatalog/public/icons/agents/openai.svg +1 -0
  57. package/eventcatalog/public/icons/protocols/mcp-dark.svg +1 -0
  58. package/eventcatalog/public/icons/protocols/mcp-light.svg +1 -0
  59. package/eventcatalog/public/icons/protocols/mcp.svg +1 -0
  60. package/eventcatalog/public/icons/tools/datadog.svg +1 -0
  61. package/eventcatalog/public/icons/tools/github.svg +1 -0
  62. package/eventcatalog/public/icons/tools/hubspot.svg +1 -0
  63. package/eventcatalog/public/icons/tools/slack.svg +1 -0
  64. package/eventcatalog/public/icons/tools/snowflake.svg +1 -0
  65. package/eventcatalog/public/icons/tools/zendesk.svg +1 -0
  66. package/eventcatalog/src/components/Badge.astro +41 -2
  67. package/eventcatalog/src/components/Grids/MessageGrid.tsx +16 -11
  68. package/eventcatalog/src/components/MDX/AgentTools/AgentTools.astro +132 -0
  69. package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +2 -0
  70. package/eventcatalog/src/components/MDX/ResourceRef/ResourceRef.astro +8 -3
  71. package/eventcatalog/src/components/MDX/components.tsx +2 -0
  72. package/eventcatalog/src/components/Search/SearchModal.tsx +3 -0
  73. package/eventcatalog/src/components/Search/search-utils.ts +2 -0
  74. package/eventcatalog/src/components/SideNav/NestedSideBar/SearchBar.tsx +3 -0
  75. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +3 -0
  76. package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +165 -0
  77. package/eventcatalog/src/components/Tables/Discover/columns.tsx +132 -7
  78. package/eventcatalog/src/components/Tables/Table.tsx +2 -0
  79. package/eventcatalog/src/components/Tables/columns/TeamsTableColumns.tsx +17 -0
  80. package/eventcatalog/src/components/Tables/columns/UserTableColumns.tsx +17 -0
  81. package/eventcatalog/src/content.config.ts +83 -25
  82. package/eventcatalog/src/enterprise/collections/resource-docs-utils.ts +7 -4
  83. package/eventcatalog/src/enterprise/mcp/mcp-server.ts +9 -2
  84. package/eventcatalog/src/enterprise/tools/catalog-tools.ts +62 -28
  85. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +13 -1
  86. package/eventcatalog/src/pages/_index.astro +1 -3
  87. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +5 -5
  88. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +5 -2
  89. package/eventcatalog/src/pages/directory/[type]/index.astro +2 -0
  90. package/eventcatalog/src/pages/discover/[type]/_index.data.ts +5 -0
  91. package/eventcatalog/src/pages/discover/[type]/index.astro +69 -23
  92. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId].mdx.ts +1 -0
  93. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +1 -0
  94. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +1 -1
  95. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +47 -2
  96. package/eventcatalog/src/pages/docs/[type]/[id]/[version].md.ts +2 -0
  97. package/eventcatalog/src/pages/docs/[type]/[id]/[version].mdx.ts +2 -0
  98. package/eventcatalog/src/pages/docs/[type]/[id]/_index.data.ts +1 -0
  99. package/eventcatalog/src/pages/docs/llm/llms-full.txt.ts +3 -0
  100. package/eventcatalog/src/pages/docs/llm/llms.txt.ts +3 -0
  101. package/eventcatalog/src/pages/docs/teams/[id]/index.astro +24 -1
  102. package/eventcatalog/src/pages/docs/users/[id]/index.astro +24 -1
  103. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +2 -1
  104. package/eventcatalog/src/stores/sidebar-store/builders/agent.ts +141 -0
  105. package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +9 -0
  106. package/eventcatalog/src/stores/sidebar-store/builders/flow.ts +19 -0
  107. package/eventcatalog/src/stores/sidebar-store/builders/message.ts +8 -2
  108. package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +10 -7
  109. package/eventcatalog/src/stores/sidebar-store/state.ts +121 -2
  110. package/eventcatalog/src/types/index.ts +3 -1
  111. package/eventcatalog/src/utils/collection-colors.ts +5 -0
  112. package/eventcatalog/src/utils/collections/agents.ts +163 -0
  113. package/eventcatalog/src/utils/collections/commands.ts +3 -2
  114. package/eventcatalog/src/utils/collections/domains.ts +94 -15
  115. package/eventcatalog/src/utils/collections/events.ts +3 -2
  116. package/eventcatalog/src/utils/collections/flows.ts +20 -3
  117. package/eventcatalog/src/utils/collections/icons.ts +3 -1
  118. package/eventcatalog/src/utils/collections/messages.ts +35 -5
  119. package/eventcatalog/src/utils/collections/queries.ts +3 -2
  120. package/eventcatalog/src/utils/collections/schemas.ts +4 -4
  121. package/eventcatalog/src/utils/collections/services.ts +1 -1
  122. package/eventcatalog/src/utils/collections/teams.ts +5 -1
  123. package/eventcatalog/src/utils/collections/types.ts +1 -0
  124. package/eventcatalog/src/utils/collections/users.ts +5 -1
  125. package/eventcatalog/src/utils/collections/util.ts +2 -0
  126. package/eventcatalog/src/utils/eventcatalog-config/catalog.ts +1 -0
  127. package/eventcatalog/src/utils/llms.ts +1 -1
  128. package/eventcatalog/src/utils/node-graphs/agents-node-graph.ts +4 -0
  129. package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +2 -2
  130. package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +42 -9
  131. package/eventcatalog/src/utils/node-graphs/export-mermaid.ts +20 -0
  132. package/eventcatalog/src/utils/node-graphs/export-node-graph.ts +4 -0
  133. package/eventcatalog/src/utils/node-graphs/flows-node-graph.ts +22 -1
  134. package/eventcatalog/src/utils/node-graphs/message-node-graph.ts +175 -98
  135. package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +117 -23
  136. package/eventcatalog/src/utils/node-graphs/utils/utils.ts +30 -0
  137. package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +2 -0
  138. package/eventcatalog/src/utils/resource-reference-colors.ts +1 -0
  139. package/package.json +11 -4
@@ -27,6 +27,7 @@ import { getQueries } from '@utils/collections/queries';
27
27
  import {
28
28
  createNode,
29
29
  buildContextMenuForMessage,
30
+ buildContextMenuForAgent,
30
31
  buildContextMenuForService,
31
32
  buildContextMenuForResource,
32
33
  getOperationFields,
@@ -34,11 +35,17 @@ import {
34
35
  DEFAULT_NODE_HEIGHT,
35
36
  } from './utils/utils';
36
37
  import { getConsumersOfMessage, getProducersOfMessage } from '@utils/collections/services';
38
+ import {
39
+ getConsumersOfMessage as getAgentConsumersOfMessage,
40
+ getProducersOfMessage as getAgentProducersOfMessage,
41
+ } from '@utils/collections/agents';
37
42
  import { getNodesAndEdgesForChannelChain } from './channel-node-graph';
38
43
  import { getChannelChain, isChannelsConnected } from '@utils/collections/channels';
39
44
  import { getChannels } from '@utils/collections/channels';
40
45
 
41
46
  type DagreGraph = any;
47
+ type RoutableResource = CollectionEntry<'agents'> | CollectionEntry<'services'>;
48
+ type ProducerConsumerResource = RoutableResource | CollectionEntry<'data-products'>;
42
49
 
43
50
  interface Props {
44
51
  id: string;
@@ -50,6 +57,115 @@ interface Props {
50
57
  channels?: CollectionEntry<'channels'>[];
51
58
  }
52
59
 
60
+ const isAgent = (resource: ProducerConsumerResource | RoutableResource): resource is CollectionEntry<'agents'> =>
61
+ resource.collection === 'agents';
62
+ const isDataProduct = (resource: ProducerConsumerResource): resource is CollectionEntry<'data-products'> =>
63
+ resource.collection === 'data-products';
64
+
65
+ const getRoutableContextMenu = (resource: RoutableResource) => {
66
+ if (isAgent(resource)) {
67
+ return buildContextMenuForAgent({
68
+ id: resource.data.id,
69
+ version: resource.data.version,
70
+ repository: resource.data.repository as { url: string },
71
+ });
72
+ }
73
+
74
+ return buildContextMenuForService({
75
+ id: resource.data.id,
76
+ version: resource.data.version,
77
+ specifications: (resource.data as any).specifications,
78
+ repository: (resource.data as any).repository,
79
+ });
80
+ };
81
+
82
+ const getRoutableNodeData = (resource: RoutableResource, mode: 'simple' | 'full') => ({
83
+ title: resource.data.id,
84
+ mode,
85
+ ...(isAgent(resource) ? { agent: { ...resource.data } } : { service: { ...resource.data } }),
86
+ contextMenu: getRoutableContextMenu(resource),
87
+ });
88
+
89
+ const sanitizeToolId = (name: string) =>
90
+ name
91
+ .replace(/[^a-zA-Z0-9]+/g, '-')
92
+ .replace(/(^-|-$)/g, '')
93
+ .toLowerCase();
94
+
95
+ const generateIdForAgentToolNode = (agent: RoutableResource, tool: { name: string; type: string }) =>
96
+ `${generateIdForNode(agent)}-tool-${sanitizeToolId(`${tool.name}-${tool.type}`)}`;
97
+
98
+ const appendAgentToolNodesAndEdges = ({
99
+ agent,
100
+ nodes,
101
+ edges,
102
+ mode,
103
+ }: {
104
+ agent: RoutableResource;
105
+ nodes: Node[];
106
+ edges: Edge[];
107
+ mode: 'simple' | 'full';
108
+ }) => {
109
+ if (!isAgent(agent)) return;
110
+
111
+ (agent.data.tools || []).forEach((tool) => {
112
+ const toolNodeId = generateIdForAgentToolNode(agent, tool);
113
+
114
+ nodes.push(
115
+ createNode({
116
+ id: toolNodeId,
117
+ type: 'agentTool',
118
+ data: {
119
+ mode,
120
+ agentTool: {
121
+ id: sanitizeToolId(`${tool.name}-${tool.type}`),
122
+ name: tool.name,
123
+ type: tool.type,
124
+ icon: tool.icon,
125
+ url: tool.url,
126
+ description: tool.description,
127
+ },
128
+ contextMenu: tool.url
129
+ ? [
130
+ {
131
+ label: 'Open tool endpoint',
132
+ href: tool.url,
133
+ external: true,
134
+ },
135
+ ]
136
+ : undefined,
137
+ },
138
+ position: { x: 0, y: 0 },
139
+ })
140
+ );
141
+
142
+ edges.push(
143
+ createEdge({
144
+ id: `${generateIdForNode(agent)}-${toolNodeId}`,
145
+ source: generateIdForNode(agent),
146
+ target: toolNodeId,
147
+ label: 'calls tool',
148
+ type: 'step',
149
+ animated: false,
150
+ data: { animated: false },
151
+ markerEnd: {
152
+ type: MarkerType.ArrowClosed,
153
+ color: '#666',
154
+ width: 20,
155
+ height: 20,
156
+ },
157
+ })
158
+ );
159
+ });
160
+ };
161
+
162
+ const getDataProductNodeData = (resource: CollectionEntry<'data-products'>, mode: 'simple' | 'full') => ({
163
+ title: resource.data.id,
164
+ mode,
165
+ dataProduct: { ...resource.data },
166
+ contextMenu: buildContextMenuForResource({ collection: 'data-products', id: resource.data.id, version: resource.data.version }),
167
+ });
168
+
53
169
  const getNodesAndEdges = async ({
54
170
  id,
55
171
  version,
@@ -101,40 +217,33 @@ const getNodesAndEdges = async ({
101
217
  type: message.collection,
102
218
  });
103
219
 
104
- const producers = (message.data.producers as (CollectionEntry<'services'> | CollectionEntry<'data-products'>)[]) || [];
105
- const consumers = (message.data.consumers as (CollectionEntry<'services'> | CollectionEntry<'data-products'>)[]) || [];
220
+ const producers = (message.data.producers as ProducerConsumerResource[]) || [];
221
+ const consumers = (message.data.consumers as ProducerConsumerResource[]) || [];
106
222
 
107
- // Track nodes that are both sent and received (only for services)
108
- const serviceProducers = producers.filter((p) => p.collection === 'services') as CollectionEntry<'services'>[];
109
- const serviceConsumers = consumers.filter((c) => c.collection === 'services') as CollectionEntry<'services'>[];
110
- const bothSentAndReceived = findMatchingNodes(serviceProducers, serviceConsumers);
223
+ // Track nodes that are both sent and received (only service-like resources)
224
+ const routableProducers = producers.filter(
225
+ (p) => p.collection === 'services' || p.collection === 'agents'
226
+ ) as RoutableResource[];
227
+ const routableConsumers = consumers.filter(
228
+ (c) => c.collection === 'services' || c.collection === 'agents'
229
+ ) as RoutableResource[];
230
+ const bothSentAndReceived = findMatchingNodes(routableProducers as any, routableConsumers as any);
111
231
 
112
232
  for (const producer of producers) {
113
- const isDataProduct = producer.collection === 'data-products';
114
-
115
- // Create the producer node with appropriate data structure
116
- const producerContextMenu = isDataProduct
117
- ? buildContextMenuForResource({ collection: 'data-products', id: producer.data.id, version: producer.data.version })
118
- : buildContextMenuForService({
119
- id: producer.data.id,
120
- version: producer.data.version,
121
- specifications: (producer.data as any).specifications,
122
- repository: (producer.data as any).repository,
123
- });
124
-
125
233
  nodes.push({
126
234
  id: generateIdForNode(producer),
127
- type: isDataProduct ? 'data-products' : producer?.collection,
235
+ type: isDataProduct(producer) ? 'data-products' : producer.collection,
128
236
  sourcePosition: 'right',
129
237
  targetPosition: 'left',
130
- data: isDataProduct
131
- ? { mode, dataProduct: { ...producer.data }, contextMenu: producerContextMenu }
132
- : { mode, service: { ...producer.data }, contextMenu: producerContextMenu },
238
+ data: isDataProduct(producer) ? getDataProductNodeData(producer, mode) : getRoutableNodeData(producer, mode),
133
239
  position: { x: 250, y: 0 },
134
240
  });
241
+ if (!isDataProduct(producer)) {
242
+ appendAgentToolNodesAndEdges({ agent: producer, nodes, edges, mode });
243
+ }
135
244
 
136
245
  // Data products don't have channel configuration, so connect directly to the message
137
- if (isDataProduct) {
246
+ if (isDataProduct(producer)) {
138
247
  const rootSourceAndTarget = {
139
248
  source: { id: generateIdForNode(producer), collection: producer.collection },
140
249
  target: { id: generateIdForNode(message), collection: message.collection },
@@ -156,11 +265,11 @@ const getNodesAndEdges = async ({
156
265
  continue;
157
266
  }
158
267
 
159
- // Service-specific channel handling
160
- const serviceProducer = producer as CollectionEntry<'services'>;
268
+ // Service/agent-specific channel handling
269
+ const routableProducer = producer as RoutableResource;
161
270
 
162
271
  // Is the producer sending this message to a channel?
163
- const producerConfigurationForMessage = serviceProducer.data.sends?.find(
272
+ const producerConfigurationForMessage = routableProducer.data.sends?.find(
164
273
  (send) => send.id === message.data.id && versionMatches(send.version, message.data.version)
165
274
  );
166
275
  const producerChannelConfiguration = producerConfigurationForMessage?.to ?? [];
@@ -250,33 +359,22 @@ const getNodesAndEdges = async ({
250
359
  }
251
360
  }
252
361
 
253
- // The messages the service sends
362
+ // The resources that consume the message
254
363
  for (const consumer of consumers) {
255
- const isDataProduct = consumer.collection === 'data-products';
256
-
257
- // Render the consumer node with appropriate data structure
258
- const consumerContextMenu = isDataProduct
259
- ? buildContextMenuForResource({ collection: 'data-products', id: consumer.data.id, version: consumer.data.version })
260
- : buildContextMenuForService({
261
- id: consumer.data.id,
262
- version: consumer.data.version,
263
- specifications: (consumer.data as any).specifications,
264
- repository: (consumer.data as any).repository,
265
- });
266
-
267
364
  nodes.push({
268
365
  id: generateIdForNode(consumer),
269
366
  sourcePosition: 'right',
270
367
  targetPosition: 'left',
271
- data: isDataProduct
272
- ? { title: consumer?.data.id, mode, dataProduct: { ...consumer.data }, contextMenu: consumerContextMenu }
273
- : { title: consumer?.data.id, mode, service: { ...consumer.data }, contextMenu: consumerContextMenu },
368
+ data: isDataProduct(consumer) ? getDataProductNodeData(consumer, mode) : getRoutableNodeData(consumer, mode),
274
369
  position: { x: 0, y: 0 },
275
- type: isDataProduct ? 'data-products' : consumer?.collection,
370
+ type: isDataProduct(consumer) ? 'data-products' : consumer.collection,
276
371
  });
372
+ if (!isDataProduct(consumer)) {
373
+ appendAgentToolNodesAndEdges({ agent: consumer, nodes, edges, mode });
374
+ }
277
375
 
278
376
  // Data products don't have channel configuration, so connect directly from the message
279
- if (isDataProduct) {
377
+ if (isDataProduct(consumer)) {
280
378
  const rootSourceAndTarget = {
281
379
  source: { id: generateIdForNode(message), collection: message.collection },
282
380
  target: { id: generateIdForNode(consumer), collection: consumer.collection },
@@ -294,11 +392,11 @@ const getNodesAndEdges = async ({
294
392
  continue;
295
393
  }
296
394
 
297
- // Service-specific channel handling
298
- const serviceConsumer = consumer as CollectionEntry<'services'>;
395
+ // Service/agent-specific channel handling
396
+ const routableConsumer = consumer as RoutableResource;
299
397
 
300
398
  // Is the consumer receiving this message from a channel?
301
- const consumerConfigurationForMessage = serviceConsumer.data.receives?.find(
399
+ const consumerConfigurationForMessage = routableConsumer.data.receives?.find(
302
400
  (receive) => receive.id === message.data.id && versionMatches(receive.version, message.data.version)
303
401
  );
304
402
  const consumerChannelConfiguration = consumerConfigurationForMessage?.from ?? [];
@@ -342,8 +440,8 @@ const getNodesAndEdges = async ({
342
440
  }
343
441
 
344
442
  // Can any of the consumer channels be linked to any of the producer channels?
345
- // Only consider service producers for channel linking (data products don't have sends/receives)
346
- const producerChannels = serviceProducers
443
+ // Only consider service-like producers for channel linking (data products don't have sends/receives)
444
+ const producerChannels = routableProducers
347
445
  .map((producer) => {
348
446
  const config = producer.data.sends?.find(
349
447
  (send) => send.id === message.data.id && versionMatches(send.version, message.data.version)
@@ -352,7 +450,7 @@ const getNodesAndEdges = async ({
352
450
  })
353
451
  .flat();
354
452
  const consumerChannels =
355
- serviceConsumer.data.receives?.find(
453
+ routableConsumer.data.receives?.find(
356
454
  (receive) => receive.id === message.data.id && versionMatches(receive.version, message.data.version)
357
455
  )?.from ?? [];
358
456
 
@@ -520,6 +618,7 @@ export const getNodesAndEdgesForConsumedMessage = ({
520
618
  message,
521
619
  targetChannels = [],
522
620
  services,
621
+ agents = [],
523
622
  channels,
524
623
  currentNodes = [],
525
624
  target,
@@ -529,9 +628,10 @@ export const getNodesAndEdgesForConsumedMessage = ({
529
628
  message: CollectionEntry<CollectionMessageTypes>;
530
629
  targetChannels?: { id: string; version: string }[];
531
630
  services: CollectionEntry<'services'>[];
631
+ agents?: CollectionEntry<'agents'>[];
532
632
  channels: CollectionEntry<'channels'>[];
533
633
  currentNodes: Node[];
534
- target: CollectionEntry<'services'>;
634
+ target: RoutableResource;
535
635
  mode?: 'simple' | 'full';
536
636
  channelMap?: Map<string, CollectionEntry<'channels'>[]>;
537
637
  }) => {
@@ -573,19 +673,11 @@ export const getNodesAndEdgesForConsumedMessage = ({
573
673
  createNode({
574
674
  id: generateIdForNode(target),
575
675
  type: target.collection,
576
- data: {
577
- mode,
578
- service: { ...target.data },
579
- contextMenu: buildContextMenuForService({
580
- id: target.data.id,
581
- version: target.data.version,
582
- specifications: target.data.specifications as { type: string; path: string }[],
583
- repository: target.data.repository as { url: string },
584
- }),
585
- },
676
+ data: getRoutableNodeData(target, mode),
586
677
  position: { x: 0, y: 0 },
587
678
  })
588
679
  );
680
+ appendAgentToolNodesAndEdges({ agent: target, nodes, edges, mode });
589
681
 
590
682
  const targetMessageConfiguration = target.data.receives?.find(
591
683
  (receive) => receive.id === message.data.id && versionMatches(receive.version, message.data.version)
@@ -596,7 +688,10 @@ export const getNodesAndEdgesForConsumedMessage = ({
596
688
  .filter((channel): channel is CollectionEntry<'channels'> => channel !== undefined);
597
689
 
598
690
  // Now we get the producers of the message and create nodes and edges for them
599
- const producers = getProducersOfMessage(services, message);
691
+ const producers = [
692
+ ...getAgentProducersOfMessage(agents, message),
693
+ ...getProducersOfMessage(services, message),
694
+ ] as RoutableResource[];
600
695
 
601
696
  const hasProducers = producers.length > 0;
602
697
  const targetHasDefinedChannels = targetChannels.length > 0;
@@ -688,19 +783,11 @@ export const getNodesAndEdgesForConsumedMessage = ({
688
783
  createNode({
689
784
  id: producerId,
690
785
  type: producer.collection,
691
- data: {
692
- mode,
693
- service: { ...producer.data },
694
- contextMenu: buildContextMenuForService({
695
- id: producer.data.id,
696
- version: producer.data.version,
697
- specifications: producer.data.specifications as { type: string; path: string }[],
698
- repository: producer.data.repository as { url: string },
699
- }),
700
- },
786
+ data: getRoutableNodeData(producer, mode),
701
787
  position: { x: 0, y: 0 },
702
788
  })
703
789
  );
790
+ appendAgentToolNodesAndEdges({ agent: producer, nodes, edges, mode });
704
791
 
705
792
  // The message is always connected directly to the producer
706
793
  edges.push(
@@ -865,6 +952,7 @@ export const getNodesAndEdgesForProducedMessage = ({
865
952
  message,
866
953
  sourceChannels,
867
954
  services,
955
+ agents = [],
868
956
  channels,
869
957
  currentNodes = [],
870
958
  currentEdges = [],
@@ -875,10 +963,11 @@ export const getNodesAndEdgesForProducedMessage = ({
875
963
  message: CollectionEntry<CollectionMessageTypes>;
876
964
  sourceChannels?: { id: string; version: string }[];
877
965
  services: CollectionEntry<'services'>[];
966
+ agents?: CollectionEntry<'agents'>[];
878
967
  channels: CollectionEntry<'channels'>[];
879
968
  currentNodes: Node[];
880
969
  currentEdges: Edge[];
881
- source: CollectionEntry<'services'>;
970
+ source: RoutableResource;
882
971
  mode?: 'simple' | 'full';
883
972
  channelMap?: Map<string, CollectionEntry<'channels'>[]>;
884
973
  }) => {
@@ -920,19 +1009,11 @@ export const getNodesAndEdgesForProducedMessage = ({
920
1009
  createNode({
921
1010
  id: generateIdForNode(source),
922
1011
  type: source.collection,
923
- data: {
924
- mode,
925
- service: { ...source.data },
926
- contextMenu: buildContextMenuForService({
927
- id: source.data.id,
928
- version: source.data.version,
929
- specifications: source.data.specifications as { type: string; path: string }[],
930
- repository: source.data.repository as { url: string },
931
- }),
932
- },
1012
+ data: getRoutableNodeData(source, mode),
933
1013
  position: { x: 0, y: 0 },
934
1014
  })
935
1015
  );
1016
+ appendAgentToolNodesAndEdges({ agent: source, nodes, edges, mode });
936
1017
 
937
1018
  // Render the edge from the producer to the message
938
1019
  edges.push(
@@ -1006,13 +1087,17 @@ export const getNodesAndEdgesForProducedMessage = ({
1006
1087
  }
1007
1088
  }
1008
1089
 
1009
- // Now we get the producers of the message and create nodes and edges for them
1010
- const consumers = getConsumersOfMessage(services, message);
1090
+ // Now we get the consumers of the message and create nodes and edges for them
1091
+ const consumers = [
1092
+ ...getAgentConsumersOfMessage(agents, message),
1093
+ ...getConsumersOfMessage(services, message),
1094
+ ] as RoutableResource[];
1011
1095
 
1012
1096
  // TODO: Make this a UI Switch in the future....
1013
- const latestConsumers = consumers.filter(
1014
- (consumer) => getLatestVersionInCollectionById(services, consumer.data.id) === consumer.data.version
1015
- );
1097
+ const latestConsumers = consumers.filter((consumer) => {
1098
+ const collection = consumer.collection === 'agents' ? agents : services;
1099
+ return getLatestVersionInCollectionById(collection as any, consumer.data.id) === consumer.data.version;
1100
+ });
1016
1101
 
1017
1102
  // Process the consumers for the message
1018
1103
  for (const consumer of latestConsumers) {
@@ -1023,19 +1108,11 @@ export const getNodesAndEdgesForProducedMessage = ({
1023
1108
  createNode({
1024
1109
  id: consumerId,
1025
1110
  type: consumer.collection,
1026
- data: {
1027
- mode,
1028
- service: { ...consumer.data },
1029
- contextMenu: buildContextMenuForService({
1030
- id: consumer.data.id,
1031
- version: consumer.data.version,
1032
- specifications: consumer.data.specifications as { type: string; path: string }[],
1033
- repository: consumer.data.repository as { url: string },
1034
- }),
1035
- },
1111
+ data: getRoutableNodeData(consumer, mode),
1036
1112
  position: { x: 0, y: 0 },
1037
1113
  })
1038
1114
  );
1115
+ appendAgentToolNodesAndEdges({ agent: consumer, nodes, edges, mode });
1039
1116
 
1040
1117
  // Check if the consumer is consuming the message from a channel
1041
1118
  const consumerConfigurationForMessage = consumer.data.receives?.find(