@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
@@ -32,7 +32,8 @@ export const projectDirBase = (() => {
32
32
 
33
33
  const withIgnoredBuildArtifacts = (patterns: string | string[]) => {
34
34
  if (process.env.IGNORE_BUILD_ARTIFACTS === 'true') {
35
- return Array.isArray(patterns) ? [...patterns, '!dist/**'] : [patterns, '!dist/**'];
35
+ const ignoredArtifacts = ['!dist/**', '!**/dist/**'];
36
+ return Array.isArray(patterns) ? [...patterns, ...ignoredArtifacts] : [patterns, ...ignoredArtifacts];
36
37
  }
37
38
  return patterns;
38
39
  };
@@ -97,7 +98,7 @@ const receivesPointer = z.object({
97
98
  const resourcePointer = z.object({
98
99
  id: z.string(),
99
100
  version: z.string().optional().default('latest'),
100
- type: z.enum(['service', 'event', 'command', 'query', 'flow', 'channel', 'domain', 'user', 'team', 'container']),
101
+ type: z.enum(['agent', 'service', 'event', 'command', 'query', 'flow', 'channel', 'domain', 'user', 'team', 'container']),
101
102
  });
102
103
 
103
104
  const changelogs = defineCollection({
@@ -133,20 +134,6 @@ const baseSchema = z.object({
133
134
  badges: z.array(badge).optional(),
134
135
  owners: z.array(ownerReference).optional(),
135
136
  schemaPath: z.string().optional(),
136
- sidebar: z
137
- .object({
138
- label: z.string().optional(),
139
- badge: z.string().optional(),
140
- color: z.string().optional(),
141
- backgroundColor: z.string().optional(),
142
- })
143
- .optional(),
144
- repository: z
145
- .object({
146
- language: z.string().optional(),
147
- url: z.string().optional(),
148
- })
149
- .optional(),
150
137
  specifications: z
151
138
  .union([
152
139
  z.object({
@@ -164,6 +151,20 @@ const baseSchema = z.object({
164
151
  ),
165
152
  ])
166
153
  .optional(),
154
+ sidebar: z
155
+ .object({
156
+ label: z.string().optional(),
157
+ badge: z.string().optional(),
158
+ color: z.string().optional(),
159
+ backgroundColor: z.string().optional(),
160
+ })
161
+ .optional(),
162
+ repository: z
163
+ .object({
164
+ language: z.string().optional(),
165
+ url: z.string().optional(),
166
+ })
167
+ .optional(),
167
168
  hidden: z.boolean().optional(),
168
169
  editUrl: z.string().optional(),
169
170
  resourceGroups: z
@@ -226,6 +227,8 @@ const baseSchema = z.object({
226
227
  .optional(),
227
228
  });
228
229
 
230
+ const agentBaseSchema = baseSchema.omit({ specifications: true });
231
+
229
232
  const flowStep = z
230
233
  .union([
231
234
  // Can be a string or a number just to reference a step
@@ -260,10 +263,11 @@ const flows = defineCollection({
260
263
  z
261
264
  .object({
262
265
  id: z.union([z.string(), z.number()]),
263
- type: z.enum(['node', 'message', 'user', 'actor']).optional(),
266
+ type: z.enum(['node', 'message', 'agent', 'user', 'actor']).optional(),
264
267
  title: z.string(),
265
268
  summary: z.string().optional(),
266
269
  message: pointer.optional(),
270
+ agent: pointer.optional(),
267
271
  service: pointer.optional(),
268
272
  flow: pointer.optional(),
269
273
  container: pointer.optional(),
@@ -312,6 +316,7 @@ const flows = defineCollection({
312
316
  // Either one or non types can be present
313
317
  const typesUsed = [
314
318
  data.message,
319
+ data.agent,
315
320
  data.service,
316
321
  data.flow,
317
322
  data.container,
@@ -496,6 +501,55 @@ const services = defineCollection({
496
501
  .extend(baseSchema.shape),
497
502
  });
498
503
 
504
+ const agentTool = z.object({
505
+ name: z.string(),
506
+ type: z.string(),
507
+ icon: z.string().optional(),
508
+ url: z.string().optional(),
509
+ description: z.string().optional(),
510
+ });
511
+
512
+ const agentModel = z.object({
513
+ provider: z.string().optional(),
514
+ name: z.string().optional(),
515
+ version: z.string().optional(),
516
+ });
517
+
518
+ const agents = defineCollection({
519
+ loader: glob({
520
+ pattern: withIgnoredBuildArtifacts(['**/agents/*/index.(md|mdx)', '**/agents/*/versioned/*/index.(md|mdx)']),
521
+ base: projectDirBase,
522
+ generateId: ({ data }) => {
523
+ return `${data.id}-${data.version}`;
524
+ },
525
+ }),
526
+ schema: z
527
+ .object({
528
+ sends: z.array(sendsPointer).optional(),
529
+ receives: z.array(receivesPointer).optional(),
530
+ writesTo: z.array(pointer).optional(),
531
+ readsFrom: z.array(pointer).optional(),
532
+ flows: z.array(pointer).optional(),
533
+ model: agentModel.optional(),
534
+ tools: z.array(agentTool).optional(),
535
+ specifications: z.undefined().optional(),
536
+ detailsPanel: z
537
+ .object({
538
+ domains: detailPanelPropertySchema.optional(),
539
+ messages: detailPanelPropertySchema.optional(),
540
+ versions: detailPanelPropertySchema.optional(),
541
+ repository: detailPanelPropertySchema.optional(),
542
+ owners: detailPanelPropertySchema.optional(),
543
+ changelog: detailPanelPropertySchema.optional(),
544
+ containers: detailPanelPropertySchema.optional(),
545
+ tools: detailPanelPropertySchema.optional(),
546
+ model: detailPanelPropertySchema.optional(),
547
+ })
548
+ .optional(),
549
+ })
550
+ .extend(baseSchema.shape),
551
+ });
552
+
499
553
  // 1) Put this near your other enums/utilities
500
554
  const containerTypeEnum = z.enum([
501
555
  // Core
@@ -566,10 +620,10 @@ const resourceDocs = defineCollection({
566
620
  // Resource-level docs are restricted to known resource paths.
567
621
  // This avoids scanning external docs such as node_modules/**/docs.
568
622
  pattern: withIgnoredBuildArtifacts([
569
- '{events,commands,queries,services,flows,containers,channels,entities,data-products}/**/docs/**/*.@(md|mdx)',
570
- '{events,commands,queries,services,flows,containers,channels,entities,data-products}/**/docs/*.@(md|mdx)',
571
- '{events,commands,queries,services,flows,containers,channels,entities,data-products}/**/versioned/*/docs/**/*.@(md|mdx)',
572
- '{events,commands,queries,services,flows,containers,channels,entities,data-products}/**/versioned/*/docs/*.@(md|mdx)',
623
+ '{agents,events,commands,queries,services,flows,containers,channels,entities,data-products}/**/docs/**/*.@(md|mdx)',
624
+ '{agents,events,commands,queries,services,flows,containers,channels,entities,data-products}/**/docs/*.@(md|mdx)',
625
+ '{agents,events,commands,queries,services,flows,containers,channels,entities,data-products}/**/versioned/*/docs/**/*.@(md|mdx)',
626
+ '{agents,events,commands,queries,services,flows,containers,channels,entities,data-products}/**/versioned/*/docs/*.@(md|mdx)',
573
627
  'domains/**/docs/**/*.@(md|mdx)',
574
628
  'domains/**/docs/*.@(md|mdx)',
575
629
  ]),
@@ -581,10 +635,10 @@ const resourceDocs = defineCollection({
581
635
  const resourceDocCategories = defineCollection({
582
636
  loader: glob({
583
637
  pattern: withIgnoredBuildArtifacts([
584
- '{events,commands,queries,services,flows,containers,channels,entities,data-products}/**/docs/**/category.json',
585
- '{events,commands,queries,services,flows,containers,channels,entities,data-products}/**/docs/**/_category_.json',
586
- '{events,commands,queries,services,flows,containers,channels,entities,data-products}/**/versioned/*/docs/**/category.json',
587
- '{events,commands,queries,services,flows,containers,channels,entities,data-products}/**/versioned/*/docs/**/_category_.json',
638
+ '{agents,events,commands,queries,services,flows,containers,channels,entities,data-products}/**/docs/**/category.json',
639
+ '{agents,events,commands,queries,services,flows,containers,channels,entities,data-products}/**/docs/**/_category_.json',
640
+ '{agents,events,commands,queries,services,flows,containers,channels,entities,data-products}/**/versioned/*/docs/**/category.json',
641
+ '{agents,events,commands,queries,services,flows,containers,channels,entities,data-products}/**/versioned/*/docs/**/_category_.json',
588
642
  'domains/**/docs/**/category.json',
589
643
  'domains/**/docs/**/_category_.json',
590
644
  'domains/**/docs/category.json',
@@ -614,6 +668,7 @@ const domains = defineCollection({
614
668
  schema: z
615
669
  .object({
616
670
  services: z.array(pointer).optional(),
671
+ agents: z.array(pointer).optional(),
617
672
  domains: z.array(pointer).optional(),
618
673
  entities: z.array(pointer).optional(),
619
674
  'data-products': z.array(pointer).optional(),
@@ -775,6 +830,7 @@ const users = defineCollection({
775
830
  email: z.string().optional(),
776
831
  slackDirectMessageUrl: z.string().optional(),
777
832
  msTeamsDirectMessageUrl: z.string().optional(),
833
+ ownedAgents: z.array(reference('agents')).optional(),
778
834
  ownedDomains: z.array(reference('domains')).optional(),
779
835
  ownedServices: z.array(reference('services')).optional(),
780
836
  ownedEvents: z.array(reference('events')).optional(),
@@ -799,6 +855,7 @@ const teams = defineCollection({
799
855
  slackDirectMessageUrl: z.string().optional(),
800
856
  msTeamsDirectMessageUrl: z.string().optional(),
801
857
  members: z.array(reference('users')).optional(),
858
+ ownedAgents: z.array(reference('agents')).optional(),
802
859
  ownedCommands: z.array(reference('commands')).optional(),
803
860
  ownedQueries: z.array(reference('queries')).optional(),
804
861
  ownedDomains: z.array(reference('domains')).optional(),
@@ -857,6 +914,7 @@ export const collections = {
857
914
  commands,
858
915
  queries,
859
916
  services,
917
+ agents,
860
918
  channels,
861
919
  users,
862
920
  teams,
@@ -12,6 +12,7 @@ import { isResourceDocsEnabled } from '../feature';
12
12
  const CACHE_ENABLED = process.env.DISABLE_EVENTCATALOG_CACHE !== 'true';
13
13
 
14
14
  export type ResourceCollection =
15
+ | 'agents'
15
16
  | 'domains'
16
17
  | 'services'
17
18
  | 'events'
@@ -167,6 +168,7 @@ const inferResourceFromFilePath = (filePath: string): InferredResource | null =>
167
168
  };
168
169
 
169
170
  const segmentMappings: Array<{ segment: string; collection: ResourceCollection }> = [
171
+ { segment: 'agents', collection: 'agents' },
170
172
  { segment: 'events', collection: 'events' },
171
173
  { segment: 'commands', collection: 'commands' },
172
174
  { segment: 'queries', collection: 'queries' },
@@ -270,8 +272,9 @@ const getResourceLookups = async (): Promise<Record<ResourceCollection, Resource
270
272
  }
271
273
 
272
274
  const lookupPromise = (async () => {
273
- const [domains, services, events, commands, queries, flows, containers, channels, entities, dataProducts] = await Promise.all(
274
- [
275
+ const [agents, domains, services, events, commands, queries, flows, containers, channels, entities, dataProducts] =
276
+ await Promise.all([
277
+ getCollection('agents'),
275
278
  getCollection('domains'),
276
279
  getCollection('services'),
277
280
  getCollection('events'),
@@ -282,10 +285,10 @@ const getResourceLookups = async (): Promise<Record<ResourceCollection, Resource
282
285
  getCollection('channels'),
283
286
  getCollection('entities'),
284
287
  getCollection('data-products'),
285
- ]
286
- );
288
+ ]);
287
289
 
288
290
  return {
291
+ agents: buildLookup(agents),
289
292
  domains: buildLookup(domains),
290
293
  services: buildLookup(services),
291
294
  events: buildLookup(events),
@@ -327,8 +327,8 @@ function createMcpServer() {
327
327
  {
328
328
  name: 'All Resources in EventCatalog',
329
329
  uri: 'eventcatalog://all',
330
- description: 'All messages, domains and services in EventCatalog',
331
- collections: ['events', 'commands', 'queries', 'services', 'domains', 'flows', 'channels', 'entities'] as const,
330
+ description: 'All messages, agents, domains and services in EventCatalog',
331
+ collections: ['events', 'commands', 'queries', 'agents', 'services', 'domains', 'flows', 'channels', 'entities'] as const,
332
332
  },
333
333
  {
334
334
  name: 'All Events in EventCatalog',
@@ -354,6 +354,12 @@ function createMcpServer() {
354
354
  description: 'All services in EventCatalog',
355
355
  collections: ['services'] as const,
356
356
  },
357
+ {
358
+ name: 'All Agents in EventCatalog',
359
+ uri: 'eventcatalog://agents',
360
+ description: 'All agents in EventCatalog',
361
+ collections: ['agents'] as const,
362
+ },
357
363
  {
358
364
  name: 'All Domains in EventCatalog',
359
365
  uri: 'eventcatalog://domains',
@@ -454,6 +460,7 @@ const mcpResources = [
454
460
  'eventcatalog://events',
455
461
  'eventcatalog://commands',
456
462
  'eventcatalog://queries',
463
+ 'eventcatalog://agents',
457
464
  'eventcatalog://services',
458
465
  'eventcatalog://domains',
459
466
  'eventcatalog://flows',
@@ -15,6 +15,7 @@ import { getUbiquitousLanguageWithSubdomains } from '@utils/collections/domains'
15
15
  import { getAbsoluteFilePathForAstroFile } from '@utils/files';
16
16
  import fs from 'node:fs';
17
17
  import { getNodesAndEdges as getNodesAndEdgesForService } from '@utils/node-graphs/services-node-graph';
18
+ import { getNodesAndEdges as getNodesAndEdgesForAgent } from '@utils/node-graphs/agents-node-graph';
18
19
  import {
19
20
  getNodesAndEdgesForCommands,
20
21
  getNodesAndEdgesForEvents,
@@ -101,6 +102,7 @@ export function paginate<T>(
101
102
 
102
103
  export const collectionSchema = z.enum([
103
104
  'events',
105
+ 'agents',
104
106
  'services',
105
107
  'commands',
106
108
  'queries',
@@ -116,6 +118,7 @@ export const collectionSchema = z.enum([
116
118
  export const messageCollectionSchema = z.enum(['events', 'commands', 'queries']);
117
119
 
118
120
  export const resourceCollectionSchema = z.enum([
121
+ 'agents',
119
122
  'services',
120
123
  'events',
121
124
  'commands',
@@ -131,6 +134,7 @@ export const visualiserCollectionSchema = z.enum([
131
134
  'events',
132
135
  'commands',
133
136
  'queries',
137
+ 'agents',
134
138
  'services',
135
139
  'domains',
136
140
  'flows',
@@ -243,6 +247,7 @@ export async function findResourcesByOwner(params: { ownerId: string }) {
243
247
  'events',
244
248
  'commands',
245
249
  'queries',
250
+ 'agents',
246
251
  'services',
247
252
  'domains',
248
253
  'flows',
@@ -279,10 +284,11 @@ export async function findResourcesByOwner(params: { ownerId: string }) {
279
284
  }
280
285
 
281
286
  /**
282
- * Get services that produce (send) a specific message
287
+ * Get resources that produce (send) a specific message
283
288
  */
284
289
  export async function getProducersOfMessage(params: { messageId: string; messageVersion: string; messageCollection: string }) {
285
- const services = await getCollection('services');
290
+ const [services, agents] = await Promise.all([getCollection('services'), getCollection('agents')]);
291
+ const routableResources = [...services, ...agents];
286
292
  const message = await getEntry(params.messageCollection as any, `${params.messageId}-${params.messageVersion}`);
287
293
 
288
294
  if (!message) {
@@ -291,8 +297,8 @@ export async function getProducersOfMessage(params: { messageId: string; message
291
297
  };
292
298
  }
293
299
 
294
- const producers = services.filter((service) => {
295
- const sends = (service.data as any).sends || [];
300
+ const producers = routableResources.filter((resource) => {
301
+ const sends = (resource.data as any).sends || [];
296
302
  return sends.some((send: any) => {
297
303
  const idMatch = send.id === params.messageId;
298
304
  if (!send.version || send.version === 'latest') return idMatch;
@@ -310,16 +316,18 @@ export async function getProducersOfMessage(params: { messageId: string; message
310
316
  id: (s.data as any).id,
311
317
  version: (s.data as any).version,
312
318
  name: (s.data as any).name || (s.data as any).id,
319
+ collection: s.collection,
313
320
  })),
314
321
  count: producers.length,
315
322
  };
316
323
  }
317
324
 
318
325
  /**
319
- * Get services that consume (receive) a specific message
326
+ * Get resources that consume (receive) a specific message
320
327
  */
321
328
  export async function getConsumersOfMessage(params: { messageId: string; messageVersion: string; messageCollection: string }) {
322
- const services = await getCollection('services');
329
+ const [services, agents] = await Promise.all([getCollection('services'), getCollection('agents')]);
330
+ const routableResources = [...services, ...agents];
323
331
  const message = await getEntry(params.messageCollection as any, `${params.messageId}-${params.messageVersion}`);
324
332
 
325
333
  if (!message) {
@@ -328,8 +336,8 @@ export async function getConsumersOfMessage(params: { messageId: string; message
328
336
  };
329
337
  }
330
338
 
331
- const consumers = services.filter((service) => {
332
- const receives = (service.data as any).receives || [];
339
+ const consumers = routableResources.filter((resource) => {
340
+ const receives = (resource.data as any).receives || [];
333
341
  return receives.some((receive: any) => {
334
342
  const idMatch = receive.id === params.messageId;
335
343
  if (!receive.version || receive.version === 'latest') return idMatch;
@@ -347,6 +355,7 @@ export async function getConsumersOfMessage(params: { messageId: string; message
347
355
  id: (s.data as any).id,
348
356
  version: (s.data as any).version,
349
357
  name: (s.data as any).name || (s.data as any).id,
358
+ collection: s.collection,
350
359
  })),
351
360
  count: consumers.length,
352
361
  };
@@ -357,7 +366,8 @@ export async function getConsumersOfMessage(params: { messageId: string; message
357
366
  * Returns all affected services (producers and consumers) and their owners
358
367
  */
359
368
  export async function analyzeChangeImpact(params: { messageId: string; messageVersion: string; messageCollection: string }) {
360
- const services = await getCollection('services');
369
+ const [services, agents] = await Promise.all([getCollection('services'), getCollection('agents')]);
370
+ const routableResources = [...services, ...agents];
361
371
  const message = await getEntry(params.messageCollection as any, `${params.messageId}-${params.messageVersion}`);
362
372
 
363
373
  if (!message) {
@@ -367,14 +377,14 @@ export async function analyzeChangeImpact(params: { messageId: string; messageVe
367
377
  }
368
378
 
369
379
  // Find producers
370
- const producers = services.filter((service) => {
371
- const sends = (service.data as any).sends || [];
380
+ const producers = routableResources.filter((resource) => {
381
+ const sends = (resource.data as any).sends || [];
372
382
  return sends.some((send: any) => send.id === params.messageId);
373
383
  });
374
384
 
375
385
  // Find consumers
376
- const consumers = services.filter((service) => {
377
- const receives = (service.data as any).receives || [];
386
+ const consumers = routableResources.filter((resource) => {
387
+ const receives = (resource.data as any).receives || [];
378
388
  return receives.some((receive: any) => receive.id === params.messageId);
379
389
  });
380
390
 
@@ -405,19 +415,27 @@ export async function analyzeChangeImpact(params: { messageId: string; messageVe
405
415
  impact: {
406
416
  producerCount: producers.length,
407
417
  consumerCount: consumers.length,
408
- totalServicesAffected: new Set([...producers, ...consumers].map((s) => (s.data as any).id)).size,
418
+ totalResourcesAffected: new Set([...producers, ...consumers].map((s) => `${s.collection}:${(s.data as any).id}`)).size,
419
+ totalServicesAffected: new Set(
420
+ [...producers, ...consumers].filter((s) => s.collection === 'services').map((s) => (s.data as any).id)
421
+ ).size,
422
+ totalAgentsAffected: new Set(
423
+ [...producers, ...consumers].filter((s) => s.collection === 'agents').map((s) => (s.data as any).id)
424
+ ).size,
409
425
  teamsAffected: Array.from(affectedOwners),
410
426
  },
411
427
  producers: producers.map((s) => ({
412
428
  id: (s.data as any).id,
413
429
  version: (s.data as any).version,
414
430
  name: (s.data as any).name || (s.data as any).id,
431
+ collection: s.collection,
415
432
  owners: (s.data as any).owners || [],
416
433
  })),
417
434
  consumers: consumers.map((s) => ({
418
435
  id: (s.data as any).id,
419
436
  version: (s.data as any).version,
420
437
  name: (s.data as any).name || (s.data as any).id,
438
+ collection: s.collection,
421
439
  owners: (s.data as any).owners || [],
422
440
  })),
423
441
  };
@@ -434,12 +452,16 @@ export async function explainBusinessFlow(params: { flowId: string; flowVersion:
434
452
  return { error: `Flow not found: ${params.flowId}-${params.flowVersion}` };
435
453
  }
436
454
 
437
- // Get related services that use this flow
438
- const services = await getCollection('services');
455
+ // Get related services and agents that use this flow
456
+ const [services, agents] = await Promise.all([getCollection('services'), getCollection('agents')]);
439
457
  const relatedServices = services.filter((service) => {
440
458
  const flows = (service.data as any).flows || [];
441
459
  return flows.some((f: any) => f.id === params.flowId);
442
460
  });
461
+ const relatedAgents = agents.filter((agent) => {
462
+ const flows = (agent.data as any).flows || [];
463
+ return flows.some((f: any) => f.id === params.flowId);
464
+ });
443
465
 
444
466
  return {
445
467
  flow: {
@@ -458,6 +480,11 @@ export async function explainBusinessFlow(params: { flowId: string; flowVersion:
458
480
  version: (s.data as any).version,
459
481
  name: (s.data as any).name || (s.data as any).id,
460
482
  })),
483
+ relatedAgents: relatedAgents.map((a) => ({
484
+ id: (a.data as any).id,
485
+ version: (a.data as any).version,
486
+ name: (a.data as any).name || (a.data as any).id,
487
+ })),
461
488
  };
462
489
  }
463
490
 
@@ -583,15 +610,16 @@ export async function findMessageBySchemaId(params: {
583
610
  const resource = matches[0];
584
611
  if (resource) {
585
612
  // Get producers and consumers
586
- const services = await getCollection('services');
613
+ const [services, agents] = await Promise.all([getCollection('services'), getCollection('agents')]);
614
+ const routableResources = [...services, ...agents];
587
615
 
588
- const producers = services.filter((service) => {
589
- const sends = (service.data as any).sends || [];
616
+ const producers = routableResources.filter((resource) => {
617
+ const sends = (resource.data as any).sends || [];
590
618
  return sends.some((send: any) => send.id === params.messageId);
591
619
  });
592
620
 
593
- const consumers = services.filter((service) => {
594
- const receives = (service.data as any).receives || [];
621
+ const consumers = routableResources.filter((resource) => {
622
+ const receives = (resource.data as any).receives || [];
595
623
  return receives.some((receive: any) => receive.id === params.messageId);
596
624
  });
597
625
 
@@ -608,11 +636,13 @@ export async function findMessageBySchemaId(params: {
608
636
  id: (s.data as any).id,
609
637
  version: (s.data as any).version,
610
638
  name: (s.data as any).name || (s.data as any).id,
639
+ collection: s.collection,
611
640
  })),
612
641
  consumers: consumers.map((s) => ({
613
642
  id: (s.data as any).id,
614
643
  version: (s.data as any).version,
615
644
  name: (s.data as any).name || (s.data as any).id,
645
+ collection: s.collection,
616
646
  })),
617
647
  };
618
648
  }
@@ -854,6 +884,7 @@ export async function getDataProductOutputs(params: { dataProductId: string; dat
854
884
  // ============================================
855
885
 
856
886
  const getNodesAndEdgesFunctions = {
887
+ agents: getNodesAndEdgesForAgent,
857
888
  services: getNodesAndEdgesForService,
858
889
  events: getNodesAndEdgesForEvents,
859
890
  commands: getNodesAndEdgesForCommands,
@@ -926,19 +957,22 @@ export async function getArchitectureDiagramAsMermaid(params: {
926
957
 
927
958
  export const toolDescriptions = {
928
959
  getResources:
929
- 'Use this tool to get events, services, commands, queries, flows, domains, channels, entities from EventCatalog. Supports pagination via cursor and filtering by search term (searches name, id, and summary).',
960
+ 'Use this tool to get events, agents, services, commands, queries, flows, domains, channels, entities from EventCatalog. Supports pagination via cursor and filtering by search term (searches name, id, and summary).',
930
961
  getResource: 'Use this tool to get a specific resource from EventCatalog by its id and version',
931
962
  getMessagesProducedOrConsumedByResource:
932
963
  'Use this tool to get the messages produced or consumed by a resource by its id and version. Look at the `sends` and `receives` properties to get the messages produced or consumed by the resource',
933
964
  getSchemaForResource:
934
965
  'Use this tool to get the schema or specifications (openapi or asyncapi or graphql) for a resource by its id and version',
935
- findResourcesByOwner: 'Use this tool to find all resources (services, events, commands, etc.) owned by a specific team or user',
936
- getProducersOfMessage: 'Use this tool to find which services produce (send) a specific message (event, command, or query)',
937
- getConsumersOfMessage: 'Use this tool to find which services consume (receive) a specific message (event, command, or query)',
966
+ findResourcesByOwner:
967
+ 'Use this tool to find all resources (agents, services, events, commands, etc.) owned by a specific team or user',
968
+ getProducersOfMessage:
969
+ 'Use this tool to find which agents or services produce (send) a specific message (event, command, or query)',
970
+ getConsumersOfMessage:
971
+ 'Use this tool to find which agents or services consume (receive) a specific message (event, command, or query)',
938
972
  analyzeChangeImpact:
939
- 'Use this tool to analyze the impact of changing a message. Returns all affected services (producers and consumers), the teams that own them, and the blast radius of the change',
973
+ 'Use this tool to analyze the impact of changing a message. Returns all affected agents and services (producers and consumers), the teams that own them, and the blast radius of the change',
940
974
  explainBusinessFlow:
941
- 'Use this tool to get detailed information about a business flow (state machine). Returns the flow definition, steps, mermaid diagram if available, and related services',
975
+ 'Use this tool to get detailed information about a business flow (state machine). Returns the flow definition, steps, mermaid diagram if available, and related agents and services',
942
976
  getTeams:
943
977
  'Use this tool to get all teams in EventCatalog. Teams are groups of users that own resources. Supports pagination via cursor.',
944
978
  getTeam: 'Use this tool to get a specific team by its id. Returns team details including members.',
@@ -954,5 +988,5 @@ export const toolDescriptions = {
954
988
  getDataProductOutputs:
955
989
  'Use this tool to get the outputs (resources produced) for a data product. Returns fully hydrated output resources with their id, version, name, summary, collection type, and data contracts (if defined). Data contracts include the contract name, path, format, type, and content.',
956
990
  getArchitectureDiagramAsMermaid:
957
- 'Use this tool to get the architecture diagram for a resource as Mermaid flowchart code. This shows how the resource connects to other resources (services, events, channels, etc.) in the architecture. The mermaid code can be rendered to visualize the architecture or used to understand relationships. Supported collections: events, commands, queries, services, domains, flows, containers, data-products.',
991
+ 'Use this tool to get the architecture diagram for a resource as Mermaid flowchart code. This shows how the resource connects to other resources (agents, services, events, channels, etc.) in the architecture. The mermaid code can be rendered to visualize the architecture or used to understand relationships. Supported collections: events, commands, queries, agents, services, domains, flows, containers, data-products.',
958
992
  };
@@ -59,6 +59,7 @@ import { getCommands } from '@utils/collections/commands';
59
59
  import { getDomains } from '@utils/collections/domains';
60
60
  import { getEvents } from '@utils/collections/events';
61
61
  import { getServices } from '@utils/collections/services';
62
+ import { getAgents } from '@utils/collections/agents';
62
63
  import { getFlows } from '@utils/collections/flows';
63
64
  import { isCollectionVisibleInCatalog } from '@eventcatalog';
64
65
  import { buildUrl } from '@utils/url-builder';
@@ -75,15 +76,17 @@ let events: any[] = [];
75
76
  let commands: any[] = [];
76
77
  let queries: any[] = [];
77
78
  let services: any[] = [];
79
+ let agents: any[] = [];
78
80
  let domains: any[] = [];
79
81
  let flows: any[] = [];
80
82
 
81
83
  if (!catalogHasDefaultLandingPageForDocs) {
82
- [events, commands, queries, services, domains, flows] = await Promise.all([
84
+ [events, commands, queries, services, agents, domains, flows] = await Promise.all([
83
85
  getEvents({ getAllVersions: false, hydrateServices: false }),
84
86
  getCommands({ getAllVersions: false, hydrateServices: false }),
85
87
  getQueries({ getAllVersions: false, hydrateServices: false }),
86
88
  getServices({ getAllVersions: false }),
89
+ getAgents({ getAllVersions: false }),
87
90
  getDomains({ getAllVersions: false }),
88
91
  getFlows({ getAllVersions: false }),
89
92
  ]);
@@ -106,6 +109,7 @@ const getDefaultUrl = (route: string, defaultValue: string) => {
106
109
  const collections = [
107
110
  { data: domains, key: 'domains' },
108
111
  { data: services, key: 'services' },
112
+ { data: agents, key: 'agents' },
109
113
  { data: events, key: 'events' },
110
114
  { data: commands, key: 'commands' },
111
115
  { data: queries, key: 'queries' },
@@ -273,6 +277,14 @@ const browseItems = filterSidebarItems(
273
277
  href: buildUrl('/discover/data-products'),
274
278
  current: currentPath === buildUrl('/discover/data-products'),
275
279
  },
280
+ {
281
+ id: '/discover/agents',
282
+ aliases: ['/discover'],
283
+ label: 'Agents',
284
+ icon: BotMessageSquare,
285
+ href: buildUrl('/discover/agents'),
286
+ current: currentPath === buildUrl('/discover/agents'),
287
+ },
276
288
  ],
277
289
  userSideBarConfiguration
278
290
  );
@@ -29,8 +29,6 @@ const queries = allQueries.filter(isCurrentVersion);
29
29
  const messages = [...events, ...commands, ...queries];
30
30
  const flows = allFlows.filter(isCurrentVersion);
31
31
 
32
- const totalResources = domains.length + services.length + messages.length + flows.length;
33
-
34
32
  const getDefaultUrl = (route: string, defaultValue: string) => {
35
33
  if (domains.length > 0) return buildUrl(`/${route}/domains/${domains[0].data.id}/${domains[0].data.version}`);
36
34
  if (services.length > 0) return buildUrl(`/${route}/services/${services[0].data.id}/${services[0].data.version}`);
@@ -106,7 +104,7 @@ const exploreCards: ExploreCard[] = [
106
104
  },
107
105
  {
108
106
  title: 'Discover',
109
- description: 'Search every event, service, and team across the catalog.',
107
+ description: 'Search every event, service, agent, and team across the catalog.',
110
108
  icon: TableProperties,
111
109
  href: buildUrl('/discover/events'),
112
110
  tone: '94 234 212', // teal-300
@@ -5,6 +5,8 @@ import { pageDataLoader } from '@utils/page-loaders/page-data-loader';
5
5
  import { getDomains } from '@utils/collections/domains';
6
6
  import { getServices } from '@utils/collections/services';
7
7
 
8
+ const architecturePageTypes: PageTypes[] = ['services', 'domains'];
9
+
8
10
  /**
9
11
  * Documentation page class for all collection types with versioning
10
12
  */
@@ -14,8 +16,6 @@ export class Page extends HybridPage {
14
16
  return [];
15
17
  }
16
18
 
17
- const itemTypes: PageTypes[] = ['services', 'domains'];
18
-
19
19
  const domains = await getDomains({ enrichServices: true });
20
20
  const services = await getServices();
21
21
 
@@ -24,12 +24,12 @@ export class Page extends HybridPage {
24
24
  return pageData.flatMap((items, index) =>
25
25
  items.map((item) => ({
26
26
  params: {
27
- type: itemTypes[index],
27
+ type: architecturePageTypes[index],
28
28
  id: item.data.id,
29
29
  version: item.data.version,
30
30
  },
31
31
  props: {
32
- type: itemTypes[index],
32
+ type: architecturePageTypes[index],
33
33
  ...item,
34
34
  // Not everything needs the body of the page itself.
35
35
  body: undefined,
@@ -41,7 +41,7 @@ export class Page extends HybridPage {
41
41
  protected static async fetchData(params: any) {
42
42
  const { type, id, version } = params;
43
43
 
44
- if (!type || !id || !version) {
44
+ if (!type || !id || !version || !architecturePageTypes.includes(type)) {
45
45
  return null;
46
46
  }
47
47