@opperai/agents 0.1.1 → 0.1.3

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.
package/dist/index.cjs CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  var crypto = require('crypto');
4
4
  var zod = require('zod');
5
+ var fs = require('fs');
5
6
  var opperai = require('opperai');
6
7
  var zodToJsonSchema = require('zod-to-json-schema');
7
8
  var index_js = require('@modelcontextprotocol/sdk/client/index.js');
@@ -467,6 +468,229 @@ var createHookManager = (logger) => new HookManager(logger);
467
468
 
468
469
  // src/base/agent.ts
469
470
  init_tool();
471
+ function sanitizeId(name) {
472
+ return name.replace(/\s/g, "_").replace(/-/g, "_").replace(/\./g, "_").replace(/[()]/g, "");
473
+ }
474
+ function sanitizeLabel(text) {
475
+ let cleaned = text.replace(/"/g, "'").replace(/\n/g, " ").replace(/`/g, "");
476
+ cleaned = cleaned.split(".")[0]?.trim() || cleaned.trim();
477
+ if (cleaned.length > 45) {
478
+ cleaned = cleaned.substring(0, 42) + "...";
479
+ }
480
+ return cleaned;
481
+ }
482
+ function getSchemaName(schema) {
483
+ if (!schema) {
484
+ return "N/A";
485
+ }
486
+ try {
487
+ const schemaAny = schema;
488
+ if (schemaAny.description) {
489
+ return schemaAny.description;
490
+ }
491
+ if (schemaAny._def?.description) {
492
+ return schemaAny._def.description;
493
+ }
494
+ const typeName = schemaAny._def?.typeName;
495
+ if (typeName === "ZodObject" && schemaAny._def) {
496
+ const shape = schemaAny._def.shape?.();
497
+ if (shape && typeof shape === "object") {
498
+ const keys = Object.keys(shape);
499
+ if (keys.length > 0) {
500
+ const keyStr = keys.length > 3 ? `{${keys.slice(0, 3).join(", ")}...}` : `{${keys.join(", ")}}`;
501
+ return keyStr;
502
+ }
503
+ }
504
+ return "Object";
505
+ }
506
+ if (typeName) {
507
+ return typeName.replace("Zod", "").replace("Type", "");
508
+ }
509
+ return "Any";
510
+ } catch {
511
+ return "Any";
512
+ }
513
+ }
514
+ function extractParameters(schema) {
515
+ if (!schema) {
516
+ return null;
517
+ }
518
+ try {
519
+ const schemaAny = schema;
520
+ if (schemaAny._def?.typeName === "ZodObject") {
521
+ const shape = schemaAny._def.shape?.();
522
+ if (shape && typeof shape === "object") {
523
+ const params = [];
524
+ for (const [key, value] of Object.entries(shape)) {
525
+ const fieldType = value?._def?.typeName;
526
+ if (fieldType) {
527
+ const cleanType = fieldType.replace("Zod", "").toLowerCase();
528
+ params.push(`${key}: ${cleanType}`);
529
+ } else {
530
+ params.push(key);
531
+ }
532
+ }
533
+ return params.length > 0 ? params : null;
534
+ }
535
+ }
536
+ return null;
537
+ } catch {
538
+ return null;
539
+ }
540
+ }
541
+ function getRegisteredHooks(hooks) {
542
+ const events = [];
543
+ const allEvents = Object.values(HookEvents);
544
+ for (const event of allEvents) {
545
+ if (hooks.listenerCount(event) > 0) {
546
+ events.push(event);
547
+ }
548
+ }
549
+ return events;
550
+ }
551
+ function getWrappedAgent(tool2) {
552
+ const wrapped = tool2.metadata?.["wrappedAgent"];
553
+ if (wrapped && typeof wrapped === "object" && "name" in wrapped) {
554
+ return wrapped;
555
+ }
556
+ return null;
557
+ }
558
+ function isMcpTool(tool2) {
559
+ return tool2.metadata?.["provider"] === "mcp";
560
+ }
561
+ async function generateAgentFlowDiagram(agent, options = {}) {
562
+ const visited = options._visited ?? /* @__PURE__ */ new Set();
563
+ const isRoot = visited.size === 0;
564
+ const lines = [];
565
+ if (isRoot) {
566
+ lines.push("```mermaid");
567
+ lines.push("graph TB");
568
+ }
569
+ const agentId = sanitizeId(agent.name);
570
+ if (visited.has(agentId)) {
571
+ return "";
572
+ }
573
+ visited.add(agentId);
574
+ let agentLabel = `\u{1F916} ${agent.name}`;
575
+ if (agent.description && agent.description !== `Agent: ${agent.name}` && agent.description !== agent.name) {
576
+ const desc = sanitizeLabel(agent.description);
577
+ agentLabel += `<br/><i>${desc}</i>`;
578
+ }
579
+ const inputSchemaName = getSchemaName(agent.inputSchema);
580
+ const outputSchemaName = getSchemaName(agent.outputSchema);
581
+ agentLabel += `<br/>In: ${inputSchemaName} | Out: ${outputSchemaName}`;
582
+ lines.push(` ${agentId}["${agentLabel}"]:::agent`);
583
+ const agentWithHooks = agent;
584
+ const registeredHooks = getRegisteredHooks(agentWithHooks.hooks);
585
+ if (registeredHooks.length > 0) {
586
+ const hookId = `${agentId}_hooks`;
587
+ const hookNames = registeredHooks.slice(0, 3).join(", ");
588
+ const hookLabel = registeredHooks.length > 3 ? `${hookNames} +${registeredHooks.length - 3}` : hookNames;
589
+ lines.push(` ${hookId}["\u{1FA9D} ${hookLabel}"]:::hook`);
590
+ lines.push(` ${agentId} -.-> ${hookId}`);
591
+ }
592
+ const tools = agent.getTools();
593
+ const regularTools = [];
594
+ const mcpToolsByServer = /* @__PURE__ */ new Map();
595
+ const agentTools = [];
596
+ for (const tool2 of tools) {
597
+ const wrappedAgent = getWrappedAgent(tool2);
598
+ if (wrappedAgent) {
599
+ agentTools.push(tool2);
600
+ } else if (isMcpTool(tool2)) {
601
+ const serverName = tool2.metadata?.["server"] ?? "unknown";
602
+ const serverTools = mcpToolsByServer.get(serverName) ?? [];
603
+ serverTools.push(tool2);
604
+ mcpToolsByServer.set(serverName, serverTools);
605
+ } else {
606
+ regularTools.push(tool2);
607
+ }
608
+ }
609
+ for (const tool2 of regularTools) {
610
+ const toolId = sanitizeId(`${agentId}_${tool2.name}`);
611
+ let toolLabel = `\u2699\uFE0F ${sanitizeLabel(tool2.name)}`;
612
+ if (tool2.description) {
613
+ const desc = sanitizeLabel(tool2.description);
614
+ toolLabel += `<br/><i>${desc}</i>`;
615
+ }
616
+ const params = extractParameters(tool2.schema);
617
+ if (params && params.length > 0) {
618
+ const paramsStr = params.length > 3 ? `${params.slice(0, 3).join(", ")}...` : params.join(", ");
619
+ toolLabel += `<br/>(${paramsStr})`;
620
+ }
621
+ lines.push(` ${toolId}["${toolLabel}"]:::tool`);
622
+ lines.push(` ${agentId} --> ${toolId}`);
623
+ }
624
+ if (mcpToolsByServer.size > 0) {
625
+ for (const [serverName, serverTools] of mcpToolsByServer.entries()) {
626
+ if (options.includeMcpTools) {
627
+ for (const tool2 of serverTools) {
628
+ const toolId = sanitizeId(`${agentId}_${tool2.name}`);
629
+ let toolLabel = `\u2699\uFE0F ${sanitizeLabel(tool2.name)}`;
630
+ if (tool2.description) {
631
+ const desc = sanitizeLabel(tool2.description);
632
+ toolLabel += `<br/><i>${desc}</i>`;
633
+ }
634
+ toolLabel += `<br/>(MCP: ${sanitizeLabel(serverName)})`;
635
+ lines.push(` ${toolId}["${toolLabel}"]:::tool`);
636
+ lines.push(` ${agentId} --> ${toolId}`);
637
+ }
638
+ } else {
639
+ const providerId = sanitizeId(`${agentId}_provider_${serverName}`);
640
+ lines.push(` ${providerId}["\u{1F50C} ${serverName}"]:::provider`);
641
+ lines.push(` ${agentId} --> ${providerId}`);
642
+ }
643
+ }
644
+ }
645
+ for (const tool2 of agentTools) {
646
+ const wrappedAgent = getWrappedAgent(tool2);
647
+ if (wrappedAgent) {
648
+ const subAgentId = sanitizeId(wrappedAgent.name);
649
+ lines.push(` ${agentId} --> ${subAgentId}`);
650
+ const subDiagram = await generateAgentFlowDiagram(wrappedAgent, {
651
+ ...options,
652
+ _visited: visited
653
+ });
654
+ const subLines = subDiagram.split("\n").filter(
655
+ (line) => line && !line.includes("```mermaid") && !line.includes("```") && !line.includes("%% Styling") && !line.includes("classDef")
656
+ );
657
+ lines.push(...subLines);
658
+ }
659
+ }
660
+ if (isRoot) {
661
+ lines.push("");
662
+ lines.push(" %% Styling - Opper Brand Colors");
663
+ lines.push(
664
+ " classDef agent fill:#8CF0DC,stroke:#1B2E40,stroke-width:3px,color:#1B2E40"
665
+ );
666
+ lines.push(
667
+ " classDef tool fill:#FFD7D7,stroke:#3C3CAF,stroke-width:2px,color:#1B2E40"
668
+ );
669
+ lines.push(
670
+ " classDef schema fill:#F8F8F8,stroke:#3C3CAF,stroke-width:2px,color:#1B2E40"
671
+ );
672
+ lines.push(
673
+ " classDef hook fill:#FFB186,stroke:#3C3CAF,stroke-width:2px,color:#1B2E40"
674
+ );
675
+ lines.push(
676
+ " classDef provider fill:#8CECF2,stroke:#1B2E40,stroke-width:2px,color:#1B2E40"
677
+ );
678
+ lines.push("```");
679
+ }
680
+ const diagram = lines.join("\n");
681
+ if (options.outputPath && isRoot) {
682
+ let filePath = options.outputPath;
683
+ if (!filePath.endsWith(".md")) {
684
+ filePath += ".md";
685
+ }
686
+ const fileContent = `# Agent Flow: ${agent.name}
687
+
688
+ ${diagram}`;
689
+ await fs.promises.writeFile(filePath, fileContent, "utf-8");
690
+ return filePath;
691
+ }
692
+ return diagram;
693
+ }
470
694
  var MemoryEntryMetadataSchema = zod.z.object({
471
695
  createdAt: zod.z.number(),
472
696
  updatedAt: zod.z.number(),
@@ -800,7 +1024,9 @@ var BaseAgent = class {
800
1024
  ...this.inputSchema && { schema: this.inputSchema },
801
1025
  metadata: {
802
1026
  isAgent: true,
803
- agentName: this.name
1027
+ agentName: this.name,
1028
+ wrappedAgent: this
1029
+ // Store reference to this agent for visualization
804
1030
  },
805
1031
  execute: async (input, executionContext) => {
806
1032
  try {
@@ -998,6 +1224,30 @@ var BaseAgent = class {
998
1224
  });
999
1225
  await Promise.allSettled(teardownPromises);
1000
1226
  }
1227
+ /**
1228
+ * Generate a Mermaid flowchart diagram visualizing the agent's structure and flow.
1229
+ * Shows tools, hooks, schemas, providers, and nested agents.
1230
+ *
1231
+ * @param options - Visualization options
1232
+ * @returns Mermaid markdown string, or file path if outputPath was provided
1233
+ *
1234
+ * @example
1235
+ * ```typescript
1236
+ * // Generate diagram string
1237
+ * const diagram = await agent.visualizeFlow();
1238
+ * console.log(diagram);
1239
+ *
1240
+ * // Save to file
1241
+ * const path = await agent.visualizeFlow({ outputPath: "agent_flow.md" });
1242
+ * console.log(`Saved to ${path}`);
1243
+ *
1244
+ * // Include MCP tools details
1245
+ * const diagram = await agent.visualizeFlow({ includeMcpTools: true });
1246
+ * ```
1247
+ */
1248
+ async visualizeFlow(options) {
1249
+ return generateAgentFlowDiagram(this, options);
1250
+ }
1001
1251
  };
1002
1252
 
1003
1253
  // src/index.ts
@@ -1090,7 +1340,7 @@ var ToolExecutionSummarySchema = zod.z.object({
1090
1340
 
1091
1341
  // package.json
1092
1342
  var package_default = {
1093
- version: "0.1.1"};
1343
+ version: "0.1.3"};
1094
1344
 
1095
1345
  // src/utils/version.ts
1096
1346
  var SDK_NAME = "@opperai/agents";
@@ -2658,6 +2908,7 @@ exports.createInMemoryStore = createInMemoryStore;
2658
2908
  exports.createMCPServerConfig = createMCPServerConfig;
2659
2909
  exports.createOpperClient = createOpperClient;
2660
2910
  exports.extractTools = extractTools;
2911
+ exports.generateAgentFlowDiagram = generateAgentFlowDiagram;
2661
2912
  exports.getDefaultLogger = getDefaultLogger;
2662
2913
  exports.getSchemaDefault = getSchemaDefault;
2663
2914
  exports.isSchemaValid = isSchemaValid;