mcp-ai-agent-guidelines
Version:
A comprehensive Model Context Protocol server providing advanced tools, resources, and prompts for implementing AI agent best practices
203 lines (201 loc) • 6.88 kB
JavaScript
/**
* Diagram Capability Handler
*
* Generates Mermaid diagrams (flowcharts, sequence diagrams, class diagrams, etc.)
* from domain results as cross-cutting artifacts.
*
* @module strategies/cross-cutting/diagram-handler
* @see {@link https://github.com/Anselmoo/mcp-ai-agent-guidelines/blob/development/plan-v0.13.x/specs/SPEC-001-output-strategy-layer.md SPEC-001 §5.3}
*/
import { CrossCuttingCapability, } from "../output-strategy.js";
/**
* Handler for generating Mermaid diagram artifacts.
*
* Detects appropriate diagram type based on domain result structure
* and generates corresponding Mermaid syntax wrapped in markdown.
*
* @implements {CapabilityHandler}
*/
export class DiagramCapabilityHandler {
capability = CrossCuttingCapability.DIAGRAM;
/**
* Generate a Mermaid diagram artifact from the context.
*
* @param context - Context with domain result and metadata
* @returns Diagram artifact or null if not applicable
*/
generate(context) {
const { domainResult, metadata } = context;
// Detect appropriate diagram type from domain result
const diagramType = this.detectDiagramType(domainResult, metadata);
// Extract description/content for diagram generation
const description = this.extractDiagramDescription(domainResult, metadata);
if (!description) {
return null;
}
// Generate Mermaid code
const mermaidCode = this.generateDiagram(diagramType, description);
// Wrap in markdown and return artifact
return {
type: this.capability,
name: `diagrams/${diagramType}-diagram.md`,
content: this.wrapInMarkdown(mermaidCode, diagramType),
};
}
/**
* Check if this handler supports the given domain type.
*
* @param domainType - Domain type identifier
* @returns True if diagrams can be generated for this type
*/
supports(domainType) {
// Support common domain types that benefit from visualization
return ["SessionState", "ScoringResult", "PromptResult"].includes(domainType);
}
/**
* Detect appropriate diagram type based on domain result structure.
*
* @param result - Domain result data
* @param metadata - Optional metadata
* @returns Diagram type identifier
*/
detectDiagramType(result, metadata) {
// Check metadata for explicit diagram type hint
if (metadata?.diagramType && typeof metadata.diagramType === "string") {
return metadata.diagramType;
}
// Detect based on domain result structure
if (result && typeof result === "object") {
const obj = result;
// Session state → flowchart showing phases
if (obj.phase || obj.phases || obj.currentPhase) {
return "flowchart";
}
// Architecture/components → class diagram
if (obj.components || obj.classes || obj.interfaces) {
return "class";
}
// Workflow/sequence → sequence diagram
if (obj.steps || obj.workflow || obj.interactions) {
return "sequence";
}
}
// Default to flowchart
return "flowchart";
}
/**
* Extract description/content for diagram generation.
*
* @param result - Domain result data
* @param metadata - Optional metadata
* @returns Description string or null if unavailable
*/
extractDiagramDescription(result, metadata) {
// Check metadata for explicit description
if (metadata?.description && typeof metadata.description === "string") {
return metadata.description;
}
// Extract from domain result
if (result && typeof result === "object") {
const obj = result;
// Common description fields
if (obj.description && typeof obj.description === "string") {
return obj.description;
}
if (obj.title && typeof obj.title === "string") {
return obj.title;
}
if (obj.summary && typeof obj.summary === "string") {
return obj.summary;
}
}
// No description available
return null;
}
/**
* Generate Mermaid diagram code based on type.
*
* @param type - Diagram type
* @param description - Content description
* @returns Mermaid syntax
*/
generateDiagram(type, description) {
switch (type) {
case "flowchart":
return this.generateFlowchart(description);
case "sequence":
return this.generateSequence(description);
case "class":
return this.generateClassDiagram(description);
default:
return this.generateFlowchart(description);
}
}
/**
* Generate a flowchart diagram.
*
* @param description - Flowchart description
* @returns Mermaid flowchart syntax
*/
generateFlowchart(description) {
// Use description in start node for context
const startLabel = description.length > 30
? `${description.substring(0, 30)}...`
: description;
return `flowchart TD
A[${startLabel}] --> B{Decision}
B -->|Yes| C[Action 1]
B -->|No| D[Action 2]
C --> E[End]
D --> E`;
}
/**
* Generate a sequence diagram.
*
* @param description - Sequence description
* @returns Mermaid sequence syntax
*/
generateSequence(description) {
// Use description in request for context
const requestLabel = description.length > 40
? `${description.substring(0, 40)}...`
: description;
return `sequenceDiagram
participant U as User
participant S as System
U->>S: ${requestLabel}
S-->>U: Response`;
}
/**
* Generate a class diagram.
*
* @param description - Class diagram description
* @returns Mermaid class diagram syntax
*/
generateClassDiagram(description) {
// Use description as class name (sanitized)
const className = description.replace(/[^a-zA-Z0-9]/g, "").substring(0, 20) || "Component";
return `classDiagram
class ${className} {
+method()
}`;
}
/**
* Wrap Mermaid code in markdown with header and footer.
*
* @param mermaidCode - Generated Mermaid syntax
* @param type - Diagram type
* @returns Markdown-formatted content
*/
wrapInMarkdown(mermaidCode, type) {
const typeTitle = type.charAt(0).toUpperCase() + type.slice(1);
return `# ${typeTitle} Diagram
\`\`\`mermaid
${mermaidCode}
\`\`\`
---
*Generated diagram*
`;
}
}
//# sourceMappingURL=diagram-handler.js.map