@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 +253 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -9
- package/dist/index.d.ts +63 -9
- package/dist/index.js +253 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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.
|
|
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;
|