@probelabs/probe 0.6.0-rc109 → 0.6.0-rc112
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/build/agent/index.js +26251 -4684
- package/build/agent/schemaUtils.js +269 -789
- package/cjs/agent/ProbeAgent.cjs +25957 -4390
- package/cjs/index.cjs +25957 -4390
- package/package.json +2 -1
- package/src/agent/schemaUtils.js +269 -789
package/src/agent/schemaUtils.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { createMessagePreview } from '../tools/common.js';
|
|
7
|
+
import { validate, fixText, extractMermaidBlocks } from '@probelabs/maid';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* HTML entity decoder map for common entities that might appear in mermaid diagrams
|
|
@@ -482,8 +483,9 @@ export function extractMermaidFromMarkdown(response) {
|
|
|
482
483
|
|
|
483
484
|
while ((match = mermaidBlockRegex.exec(response)) !== null) {
|
|
484
485
|
const attributes = match[1] ? match[1].trim() : '';
|
|
485
|
-
|
|
486
|
-
|
|
486
|
+
// Don't trim the content - maid 0.0.6 requires trailing newlines for sequence diagrams
|
|
487
|
+
const fullContent = match[2];
|
|
488
|
+
|
|
487
489
|
// If attributes exist, they were captured separately, so fullContent is just the diagram
|
|
488
490
|
// If no attributes, the first line of fullContent might be diagram type or actual content
|
|
489
491
|
diagrams.push({
|
|
@@ -544,135 +546,47 @@ export async function validateMermaidDiagram(diagram) {
|
|
|
544
546
|
}
|
|
545
547
|
|
|
546
548
|
try {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
+
// Don't trim the diagram - maid 0.0.6 requires trailing newlines for sequence diagrams
|
|
550
|
+
// and handles leading/trailing whitespace correctly
|
|
551
|
+
|
|
549
552
|
// Check for markdown code block markers
|
|
550
|
-
if (
|
|
551
|
-
return {
|
|
552
|
-
isValid: false,
|
|
553
|
+
if (diagram.includes('```')) {
|
|
554
|
+
return {
|
|
555
|
+
isValid: false,
|
|
553
556
|
error: 'Diagram contains markdown code block markers',
|
|
554
557
|
detailedError: 'Mermaid diagram should not contain ``` markers when extracted from markdown'
|
|
555
558
|
};
|
|
556
559
|
}
|
|
557
560
|
|
|
558
|
-
//
|
|
559
|
-
const
|
|
560
|
-
{ pattern: /^(graph|flowchart)/i, type: 'flowchart' },
|
|
561
|
-
{ pattern: /^sequenceDiagram/i, type: 'sequence' },
|
|
562
|
-
{ pattern: /^gantt/i, type: 'gantt' },
|
|
563
|
-
{ pattern: /^pie/i, type: 'pie' },
|
|
564
|
-
{ pattern: /^stateDiagram/i, type: 'state' },
|
|
565
|
-
{ pattern: /^classDiagram/i, type: 'class' },
|
|
566
|
-
{ pattern: /^erDiagram/i, type: 'er' },
|
|
567
|
-
{ pattern: /^journey/i, type: 'journey' },
|
|
568
|
-
{ pattern: /^gitgraph/i, type: 'gitgraph' },
|
|
569
|
-
{ pattern: /^requirementDiagram/i, type: 'requirement' },
|
|
570
|
-
{ pattern: /^C4Context/i, type: 'c4' },
|
|
571
|
-
];
|
|
561
|
+
// Use maid to validate the diagram
|
|
562
|
+
const result = validate(diagram);
|
|
572
563
|
|
|
573
|
-
//
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
if (!diagramType) {
|
|
583
|
-
return {
|
|
584
|
-
isValid: false,
|
|
585
|
-
error: 'Diagram does not match any known Mermaid diagram pattern',
|
|
586
|
-
detailedError: 'The diagram must start with a valid Mermaid diagram type (graph, sequenceDiagram, gantt, pie, etc.)'
|
|
564
|
+
// Maid returns { type: string, errors: array }
|
|
565
|
+
// Valid if errors array is empty
|
|
566
|
+
if (result.errors && result.errors.length === 0) {
|
|
567
|
+
return {
|
|
568
|
+
isValid: true,
|
|
569
|
+
diagramType: result.type || 'unknown'
|
|
587
570
|
};
|
|
588
|
-
}
|
|
571
|
+
} else {
|
|
572
|
+
// Format maid errors into a readable error message
|
|
573
|
+
const errorMessages = (result.errors || []).map(err => {
|
|
574
|
+
const location = err.line ? `line ${err.line}${err.column ? `:${err.column}` : ''}` : '';
|
|
575
|
+
return location ? `${location} - ${err.message}` : err.message;
|
|
576
|
+
});
|
|
589
577
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
// Check for GitHub-incompatible patterns that cause "got 'PS'" errors
|
|
598
|
-
if (diagramType === 'flowchart') {
|
|
599
|
-
// Check for unbalanced brackets in node labels
|
|
600
|
-
const brackets = line.match(/\[[^\]]*$/); // Unclosed bracket
|
|
601
|
-
if (brackets) {
|
|
602
|
-
return {
|
|
603
|
-
isValid: false,
|
|
604
|
-
error: `Unclosed bracket on line ${i + 1}`,
|
|
605
|
-
detailedError: `Line "${line}" contains an unclosed bracket`
|
|
606
|
-
};
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
// GitHub-strict: Check for parentheses inside node labels (causes PS token error)
|
|
610
|
-
// But allow parentheses inside double-quoted strings
|
|
611
|
-
const nodeWithParens = line.match(/\[[^"\[\]]*\([^"\[\]]*\]/);
|
|
612
|
-
if (nodeWithParens) {
|
|
613
|
-
return {
|
|
614
|
-
isValid: false,
|
|
615
|
-
error: `Parentheses in node label on line ${i + 1} (GitHub incompatible)`,
|
|
616
|
-
detailedError: `Line "${line}" contains parentheses inside node label brackets. GitHub mermaid renderer fails with 'got PS' error. Use quotes or escape characters instead.`
|
|
617
|
-
};
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
// GitHub-strict: Check for single quotes and backticks inside node labels (causes PS token error)
|
|
621
|
-
const nodeWithQuotes = line.match(/\{[^{}]*['`][^{}]*\}|\[[^[\]]*['`][^[\]]*\]/);
|
|
622
|
-
if (nodeWithQuotes) {
|
|
623
|
-
const hasBacktick = line.includes('`');
|
|
624
|
-
const quoteType = hasBacktick ? 'backticks' : 'single quotes';
|
|
625
|
-
return {
|
|
626
|
-
isValid: false,
|
|
627
|
-
error: `${hasBacktick ? 'Backticks' : 'Single quotes'} in node label on line ${i + 1} (GitHub incompatible)`,
|
|
628
|
-
detailedError: `Line "${line}" contains ${quoteType} inside node label. GitHub mermaid renderer fails with 'got PS' error. Use double quotes or escape characters instead.`
|
|
629
|
-
};
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
// GitHub-strict: Check for complex expressions inside diamond nodes
|
|
633
|
-
// Allow double-quoted strings in diamond nodes, but catch problematic single quotes and complex expressions
|
|
634
|
-
// Allow HTML breaks (<br/>, <br>, etc.) but catch other problematic patterns
|
|
635
|
-
const diamondWithComplexContent = line.match(/\{[^"{}]*[()'"<>&][^"{}]*\}/);
|
|
636
|
-
const hasHtmlBreak = line.match(/\{[^{}]*<br\s*\/?>.*\}/);
|
|
637
|
-
if (diamondWithComplexContent && !line.match(/\{\"[^\"]*\"\}/) && !hasHtmlBreak) {
|
|
638
|
-
return {
|
|
639
|
-
isValid: false,
|
|
640
|
-
error: `Complex expression in diamond node on line ${i + 1} (GitHub incompatible)`,
|
|
641
|
-
detailedError: `Line "${line}" contains special characters in diamond node that may cause GitHub parsing errors. Use simpler text or escape characters.`
|
|
642
|
-
};
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
// GitHub-strict: Check for parentheses in subgraph labels (causes PS token error)
|
|
646
|
-
if (line.startsWith('subgraph ') && line.match(/subgraph\s+[^"]*\([^"]*\)/)) {
|
|
647
|
-
return {
|
|
648
|
-
isValid: false,
|
|
649
|
-
error: `Parentheses in subgraph label on line ${i + 1} (GitHub incompatible)`,
|
|
650
|
-
detailedError: `Line "${line}" contains parentheses in subgraph label. GitHub mermaid renderer fails with 'got PS' error. Use quotes around the label or avoid parentheses.`
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
if (diagramType === 'sequence') {
|
|
656
|
-
// Check for missing colon in sequence messages
|
|
657
|
-
if (line.includes('->>') && !line.includes(':')) {
|
|
658
|
-
return {
|
|
659
|
-
isValid: false,
|
|
660
|
-
error: `Missing colon in sequence message on line ${i + 1}`,
|
|
661
|
-
detailedError: `Line "${line}" appears to be a sequence message but is missing a colon`
|
|
662
|
-
};
|
|
663
|
-
}
|
|
664
|
-
}
|
|
578
|
+
return {
|
|
579
|
+
isValid: false,
|
|
580
|
+
diagramType: result.type || 'unknown',
|
|
581
|
+
error: errorMessages[0] || 'Validation failed',
|
|
582
|
+
detailedError: errorMessages.join('\n'),
|
|
583
|
+
errors: result.errors || [] // Include raw maid errors for AI fixing
|
|
584
|
+
};
|
|
665
585
|
}
|
|
666
586
|
|
|
667
|
-
// If we get here, basic validation passed
|
|
668
|
-
return {
|
|
669
|
-
isValid: true,
|
|
670
|
-
diagramType
|
|
671
|
-
};
|
|
672
|
-
|
|
673
587
|
} catch (error) {
|
|
674
|
-
return {
|
|
675
|
-
isValid: false,
|
|
588
|
+
return {
|
|
589
|
+
isValid: false,
|
|
676
590
|
error: error.message || 'Unknown mermaid parsing error',
|
|
677
591
|
detailedError: error.stack || error.toString()
|
|
678
592
|
};
|
|
@@ -758,6 +672,61 @@ Ensure all Mermaid diagrams are properly formatted within \`\`\`mermaid code blo
|
|
|
758
672
|
return prompt;
|
|
759
673
|
}
|
|
760
674
|
|
|
675
|
+
/**
|
|
676
|
+
* Use maid to attempt auto-fixing of mermaid diagrams
|
|
677
|
+
* @param {string} diagramContent - The diagram content to fix
|
|
678
|
+
* @param {Object} options - Fix options
|
|
679
|
+
* @returns {Object} - {fixed: string, wasFixed: boolean, errors: Array}
|
|
680
|
+
*/
|
|
681
|
+
export async function tryMaidAutoFix(diagramContent, options = {}) {
|
|
682
|
+
const { debug = false } = options;
|
|
683
|
+
|
|
684
|
+
try {
|
|
685
|
+
// Always use 'all' level fixes (most aggressive)
|
|
686
|
+
if (debug) {
|
|
687
|
+
console.log(`[DEBUG] Mermaid maid: Trying 'all' level auto-fixes...`);
|
|
688
|
+
}
|
|
689
|
+
const result = fixText(diagramContent, { level: 'all' });
|
|
690
|
+
const validation = validate(result.fixed);
|
|
691
|
+
|
|
692
|
+
// Maid validation returns { type, errors }
|
|
693
|
+
// Valid if errors array is empty
|
|
694
|
+
if (validation.errors && validation.errors.length === 0) {
|
|
695
|
+
if (debug) {
|
|
696
|
+
console.log(`[DEBUG] Mermaid maid: 'All' level fixes succeeded`);
|
|
697
|
+
}
|
|
698
|
+
return {
|
|
699
|
+
fixed: result.fixed,
|
|
700
|
+
wasFixed: result.fixed !== diagramContent,
|
|
701
|
+
errors: [],
|
|
702
|
+
fixLevel: 'all'
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// Maid couldn't fix it completely, return the best attempt with remaining errors
|
|
707
|
+
if (debug) {
|
|
708
|
+
console.log(`[DEBUG] Mermaid maid: Auto-fixes couldn't resolve all issues, ${validation.errors?.length || 0} errors remain`);
|
|
709
|
+
}
|
|
710
|
+
return {
|
|
711
|
+
fixed: result.fixed,
|
|
712
|
+
wasFixed: result.fixed !== diagramContent,
|
|
713
|
+
errors: validation.errors || [], // Pass maid's structured errors for AI fixing
|
|
714
|
+
fixLevel: 'all'
|
|
715
|
+
};
|
|
716
|
+
|
|
717
|
+
} catch (error) {
|
|
718
|
+
if (debug) {
|
|
719
|
+
console.error(`[DEBUG] Mermaid maid: Auto-fix error: ${error.message}`);
|
|
720
|
+
}
|
|
721
|
+
return {
|
|
722
|
+
fixed: diagramContent,
|
|
723
|
+
wasFixed: false,
|
|
724
|
+
errors: [{ message: error.message }],
|
|
725
|
+
fixLevel: null
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
761
730
|
/**
|
|
762
731
|
* Specialized Mermaid diagram fixing agent
|
|
763
732
|
* Uses a separate ProbeAgent instance optimized for Mermaid syntax correction
|
|
@@ -881,17 +850,30 @@ When presented with a broken Mermaid diagram, analyze it thoroughly and provide
|
|
|
881
850
|
|
|
882
851
|
await this.initializeAgent();
|
|
883
852
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
853
|
+
// Format error context - handle both simple strings and maid's structured errors
|
|
854
|
+
let errorContext = '';
|
|
855
|
+
if (originalErrors.length > 0) {
|
|
856
|
+
const formattedErrors = originalErrors.map(err => {
|
|
857
|
+
// Check if this is a maid structured error object
|
|
858
|
+
if (typeof err === 'object' && err.message) {
|
|
859
|
+
const location = err.line ? `line ${err.line}${err.column ? `:${err.column}` : ''}` : '';
|
|
860
|
+
const hint = err.hint ? `\n Hint: ${err.hint}` : '';
|
|
861
|
+
return location ? `- ${location}: ${err.message}${hint}` : `- ${err.message}${hint}`;
|
|
862
|
+
}
|
|
863
|
+
// Handle simple string errors
|
|
864
|
+
return `- ${err}`;
|
|
865
|
+
}).join('\n');
|
|
866
|
+
|
|
867
|
+
errorContext = `\n\nDetected errors:\n${formattedErrors}`;
|
|
868
|
+
}
|
|
887
869
|
|
|
888
|
-
const diagramTypeHint = diagramInfo.diagramType
|
|
889
|
-
? `\n\nExpected diagram type: ${diagramInfo.diagramType}`
|
|
870
|
+
const diagramTypeHint = diagramInfo.diagramType
|
|
871
|
+
? `\n\nExpected diagram type: ${diagramInfo.diagramType}`
|
|
890
872
|
: '';
|
|
891
873
|
|
|
892
874
|
// Use decoded content for AI fixing to ensure HTML entities are handled
|
|
893
875
|
const contentToFix = decodedContent !== diagramContent ? decodedContent : diagramContent;
|
|
894
|
-
|
|
876
|
+
|
|
895
877
|
const prompt = `Analyze and fix the following Mermaid diagram.${errorContext}${diagramTypeHint}
|
|
896
878
|
|
|
897
879
|
Broken Mermaid diagram:
|
|
@@ -958,54 +940,35 @@ Provide only the corrected Mermaid diagram within a mermaid code block. Do not a
|
|
|
958
940
|
}
|
|
959
941
|
|
|
960
942
|
/**
|
|
961
|
-
*
|
|
962
|
-
*
|
|
963
|
-
* @param {
|
|
964
|
-
* @
|
|
943
|
+
* Validate and fix Mermaid diagrams using maid
|
|
944
|
+
* Replaces old manual fix logic with maid's auto-fix capabilities
|
|
945
|
+
* @param {string} response - Response containing mermaid diagrams
|
|
946
|
+
* @param {Object} options - Validation options
|
|
947
|
+
* @returns {Promise<Object>} - Validation and fixing results
|
|
965
948
|
*/
|
|
966
949
|
export async function validateAndFixMermaidResponse(response, options = {}) {
|
|
967
950
|
const { schema, debug, path, provider, model, tracer } = options;
|
|
968
951
|
const startTime = Date.now();
|
|
969
|
-
|
|
952
|
+
|
|
970
953
|
if (debug) {
|
|
971
|
-
console.log(`[DEBUG] Mermaid validation: Starting
|
|
972
|
-
console.log(`[DEBUG] Mermaid validation: Options - path: ${path}, provider: ${provider}, model: ${model}`);
|
|
954
|
+
console.log(`[DEBUG] Mermaid validation: Starting maid-based validation for response (${response.length} chars)`);
|
|
973
955
|
}
|
|
974
956
|
|
|
975
|
-
/**
|
|
976
|
-
* Helper function to determine if node content needs quoting due to problematic characters
|
|
977
|
-
* @param {string} content - The node content to check
|
|
978
|
-
* @returns {boolean} - True if content needs to be quoted
|
|
979
|
-
*/
|
|
980
|
-
const needsQuoting = (content) => {
|
|
981
|
-
return /[()'"<>&`]/.test(content) || // Core problematic characters
|
|
982
|
-
content.includes('e.g.') ||
|
|
983
|
-
content.includes('i.e.') ||
|
|
984
|
-
content.includes('src/') ||
|
|
985
|
-
content.includes('defaults/') ||
|
|
986
|
-
content.includes('.ts') ||
|
|
987
|
-
content.includes('.js') ||
|
|
988
|
-
content.includes('.yaml') ||
|
|
989
|
-
content.includes('.json') ||
|
|
990
|
-
content.includes('.md') ||
|
|
991
|
-
content.includes('.html') ||
|
|
992
|
-
content.includes('.css');
|
|
993
|
-
};
|
|
994
|
-
|
|
995
957
|
// Record mermaid validation start in telemetry
|
|
996
958
|
if (tracer) {
|
|
997
959
|
tracer.recordMermaidValidationEvent('started', {
|
|
998
960
|
'mermaid_validation.response_length': response.length,
|
|
999
961
|
'mermaid_validation.provider': provider,
|
|
1000
|
-
'mermaid_validation.model': model
|
|
962
|
+
'mermaid_validation.model': model,
|
|
963
|
+
'mermaid_validation.method': 'maid'
|
|
1001
964
|
});
|
|
1002
965
|
}
|
|
1003
|
-
|
|
966
|
+
|
|
1004
967
|
// First, run standard validation
|
|
1005
968
|
const validationStart = Date.now();
|
|
1006
969
|
const validation = await validateMermaidResponse(response);
|
|
1007
970
|
const validationTime = Date.now() - validationStart;
|
|
1008
|
-
|
|
971
|
+
|
|
1009
972
|
if (debug) {
|
|
1010
973
|
console.log(`[DEBUG] Mermaid validation: Initial validation completed in ${validationTime}ms`);
|
|
1011
974
|
console.log(`[DEBUG] Mermaid validation: Found ${validation.diagrams?.length || 0} diagrams, valid: ${validation.isValid}`);
|
|
@@ -1018,24 +981,13 @@ export async function validateAndFixMermaidResponse(response, options = {}) {
|
|
|
1018
981
|
});
|
|
1019
982
|
}
|
|
1020
983
|
}
|
|
1021
|
-
|
|
1022
|
-
// Always check for HTML entities, even if diagrams are technically valid
|
|
1023
|
-
let needsHtmlEntityCheck = false;
|
|
1024
|
-
if (validation.diagrams && validation.diagrams.length > 0) {
|
|
1025
|
-
for (const diagram of validation.diagrams) {
|
|
1026
|
-
if (diagram.content && (diagram.content.includes('<') || diagram.content.includes('>') || diagram.content.includes('&') || diagram.content.includes('"') || diagram.content.includes('''))) {
|
|
1027
|
-
needsHtmlEntityCheck = true;
|
|
1028
|
-
break;
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
984
|
|
|
1033
|
-
|
|
985
|
+
// If all valid, return early
|
|
986
|
+
if (validation.isValid) {
|
|
1034
987
|
if (debug) {
|
|
1035
|
-
console.log(`[DEBUG] Mermaid validation: All diagrams valid
|
|
988
|
+
console.log(`[DEBUG] Mermaid validation: All diagrams valid, no fixing needed`);
|
|
1036
989
|
}
|
|
1037
|
-
|
|
1038
|
-
// Record successful validation in telemetry
|
|
990
|
+
|
|
1039
991
|
if (tracer) {
|
|
1040
992
|
tracer.recordMermaidValidationEvent('completed', {
|
|
1041
993
|
'mermaid_validation.success': true,
|
|
@@ -1044,8 +996,7 @@ export async function validateAndFixMermaidResponse(response, options = {}) {
|
|
|
1044
996
|
'mermaid_validation.duration_ms': Date.now() - startTime
|
|
1045
997
|
});
|
|
1046
998
|
}
|
|
1047
|
-
|
|
1048
|
-
// All diagrams are valid and no HTML entities found, no fixing needed
|
|
999
|
+
|
|
1049
1000
|
return {
|
|
1050
1001
|
...validation,
|
|
1051
1002
|
wasFixed: false,
|
|
@@ -1054,10 +1005,10 @@ export async function validateAndFixMermaidResponse(response, options = {}) {
|
|
|
1054
1005
|
};
|
|
1055
1006
|
}
|
|
1056
1007
|
|
|
1057
|
-
// If no diagrams found
|
|
1008
|
+
// If no diagrams found, return without fixing
|
|
1058
1009
|
if (!validation.diagrams || validation.diagrams.length === 0) {
|
|
1059
1010
|
if (debug) {
|
|
1060
|
-
console.log(`[DEBUG] Mermaid validation: No mermaid diagrams found in response
|
|
1011
|
+
console.log(`[DEBUG] Mermaid validation: No mermaid diagrams found in response`);
|
|
1061
1012
|
}
|
|
1062
1013
|
return {
|
|
1063
1014
|
...validation,
|
|
@@ -1067,596 +1018,147 @@ export async function validateAndFixMermaidResponse(response, options = {}) {
|
|
|
1067
1018
|
};
|
|
1068
1019
|
}
|
|
1069
1020
|
|
|
1070
|
-
// Try
|
|
1021
|
+
// Try maid auto-fix for invalid diagrams
|
|
1071
1022
|
const invalidCount = validation.diagrams.filter(d => !d.isValid).length;
|
|
1072
1023
|
if (debug) {
|
|
1073
|
-
|
|
1074
|
-
console.log(`[DEBUG] Mermaid validation: ${invalidCount} invalid diagrams detected, trying HTML entity auto-fix first...`);
|
|
1075
|
-
} else {
|
|
1076
|
-
console.log(`[DEBUG] Mermaid validation: Diagrams are valid but HTML entities detected, applying HTML entity auto-fix...`);
|
|
1077
|
-
}
|
|
1024
|
+
console.log(`[DEBUG] Mermaid validation: ${invalidCount} invalid diagrams, trying maid auto-fix...`);
|
|
1078
1025
|
}
|
|
1079
1026
|
|
|
1080
1027
|
try {
|
|
1081
1028
|
let fixedResponse = response;
|
|
1082
1029
|
const fixingResults = [];
|
|
1083
|
-
let
|
|
1084
|
-
|
|
1085
|
-
// Extract diagrams with position information
|
|
1030
|
+
let maidFixesApplied = false;
|
|
1031
|
+
|
|
1032
|
+
// Extract diagrams with position information
|
|
1086
1033
|
const { diagrams } = extractMermaidFromMarkdown(response);
|
|
1087
|
-
|
|
1088
|
-
//
|
|
1089
|
-
|
|
1090
|
-
const allDiagrams = validation.diagrams
|
|
1034
|
+
|
|
1035
|
+
// Process invalid diagrams in reverse to maintain indices
|
|
1036
|
+
const invalidDiagrams = validation.diagrams
|
|
1091
1037
|
.map((result, index) => ({ ...result, originalIndex: index }))
|
|
1038
|
+
.filter(result => !result.isValid)
|
|
1092
1039
|
.reverse();
|
|
1093
1040
|
|
|
1094
|
-
for (const
|
|
1095
|
-
const originalContent =
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
fixedResponse.slice(originalDiagram.endIndex);
|
|
1111
|
-
|
|
1112
|
-
fixingResults.push({
|
|
1113
|
-
diagramIndex: diagram.originalIndex,
|
|
1114
|
-
wasFixed: true,
|
|
1115
|
-
originalContent: originalContent,
|
|
1116
|
-
fixedContent: decodedContent,
|
|
1117
|
-
originalError: diagram.error || 'HTML entity cleanup',
|
|
1118
|
-
fixedWithHtmlDecoding: true
|
|
1119
|
-
});
|
|
1120
|
-
|
|
1121
|
-
htmlEntityFixesApplied = true;
|
|
1122
|
-
|
|
1123
|
-
if (debug) {
|
|
1124
|
-
console.log(`[DEBUG] Mermaid validation: Fixed diagram ${diagram.originalIndex + 1} with HTML entity decoding`);
|
|
1125
|
-
console.log(`[DEBUG] Mermaid validation: Original status: ${diagram.isValid ? 'valid' : 'invalid'} - ${diagram.error || 'no error'}`);
|
|
1126
|
-
console.log(`[DEBUG] Mermaid validation: Decoded HTML entities`);
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
} catch (error) {
|
|
1130
|
-
if (debug) {
|
|
1131
|
-
console.log(`[DEBUG] Mermaid validation: HTML entity decoding didn't improve diagram ${diagram.originalIndex + 1}: ${error.message}`);
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
|
|
1137
|
-
// If HTML entity fixes were applied, re-validate the entire response
|
|
1138
|
-
if (htmlEntityFixesApplied) {
|
|
1139
|
-
const revalidation = await validateMermaidResponse(fixedResponse);
|
|
1140
|
-
if (revalidation.isValid) {
|
|
1141
|
-
// All diagrams are now valid, return without AI fixing
|
|
1142
|
-
const totalTime = Date.now() - startTime;
|
|
1143
|
-
if (debug) {
|
|
1144
|
-
console.log(`[DEBUG] Mermaid validation: All diagrams fixed with HTML entity decoding in ${totalTime}ms, no AI needed`);
|
|
1145
|
-
console.log(`[DEBUG] Mermaid validation: Applied ${fixingResults.length} HTML entity fixes`);
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
// Record HTML entity fix success in telemetry
|
|
1149
|
-
if (tracer) {
|
|
1150
|
-
tracer.recordMermaidValidationEvent('html_fix_completed', {
|
|
1151
|
-
'mermaid_validation.success': true,
|
|
1152
|
-
'mermaid_validation.fix_method': 'html_entity_decoding',
|
|
1153
|
-
'mermaid_validation.diagrams_fixed': fixingResults.length,
|
|
1154
|
-
'mermaid_validation.duration_ms': totalTime
|
|
1155
|
-
});
|
|
1156
|
-
}
|
|
1157
|
-
return {
|
|
1158
|
-
...revalidation,
|
|
1159
|
-
wasFixed: true,
|
|
1160
|
-
originalResponse: response,
|
|
1161
|
-
fixedResponse: fixedResponse,
|
|
1162
|
-
fixingResults: fixingResults
|
|
1163
|
-
};
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
// Proactive pass: Fix common node label issues in ALL diagrams (not just invalid ones)
|
|
1168
|
-
let proactiveFixesApplied = false;
|
|
1169
|
-
|
|
1170
|
-
// Re-extract diagrams after HTML entity fixes
|
|
1171
|
-
const { diagrams: currentDiagrams } = extractMermaidFromMarkdown(fixedResponse);
|
|
1172
|
-
|
|
1173
|
-
for (let diagramIndex = currentDiagrams.length - 1; diagramIndex >= 0; diagramIndex--) {
|
|
1174
|
-
const diagram = currentDiagrams[diagramIndex];
|
|
1175
|
-
const originalContent = diagram.content;
|
|
1176
|
-
const lines = originalContent.split('\n');
|
|
1177
|
-
let wasFixed = false;
|
|
1178
|
-
|
|
1179
|
-
// Proactively fix node labels that contain special characters
|
|
1180
|
-
const fixedLines = lines.map(line => {
|
|
1181
|
-
const trimmedLine = line.trim();
|
|
1182
|
-
let modifiedLine = line;
|
|
1183
|
-
|
|
1184
|
-
// Enhanced auto-fixing for square bracket nodes [...]
|
|
1185
|
-
if (trimmedLine.match(/\[[^\]]*\]/)) {
|
|
1186
|
-
modifiedLine = modifiedLine.replace(/\[([^\]]*)\]/g, (match, content) => {
|
|
1187
|
-
// Check if already properly quoted with outer quotes
|
|
1188
|
-
if (content.trim().startsWith('"') && content.trim().endsWith('"')) {
|
|
1189
|
-
// Extract the inner content (between the outer quotes)
|
|
1190
|
-
const innerContent = content.trim().slice(1, -1);
|
|
1191
|
-
// Check if inner content has unescaped quotes that need escaping
|
|
1192
|
-
if (innerContent.includes('"') || innerContent.includes("'")) {
|
|
1193
|
-
wasFixed = true;
|
|
1194
|
-
// Decode any existing HTML entities first, then re-encode ALL quotes
|
|
1195
|
-
const decodedContent = decodeHtmlEntities(innerContent);
|
|
1196
|
-
const safeContent = decodedContent
|
|
1197
|
-
.replace(/"/g, '"') // Replace ALL double quotes with HTML entity
|
|
1198
|
-
.replace(/'/g, '''); // Replace ALL single quotes with HTML entity
|
|
1199
|
-
return `["${safeContent}"]`;
|
|
1200
|
-
}
|
|
1201
|
-
return match;
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
|
-
// Check if content needs quoting (contains problematic patterns)
|
|
1205
|
-
if (needsQuoting(content)) {
|
|
1206
|
-
wasFixed = true;
|
|
1207
|
-
// Use HTML entities for quotes as per Mermaid best practices:
|
|
1208
|
-
// - GitHub doesn't support single quotes in node labels (causes 'got PS' error)
|
|
1209
|
-
// - HTML entities are the official way to escape quotes in Mermaid
|
|
1210
|
-
// - Always use double quotes with square brackets ["..."] for node labels
|
|
1211
|
-
// IMPORTANT: Decode any existing HTML entities first to avoid double-encoding
|
|
1212
|
-
const decodedContent = decodeHtmlEntities(content);
|
|
1213
|
-
const safeContent = decodedContent
|
|
1214
|
-
.replace(/"/g, '"') // Replace double quotes with HTML entity
|
|
1215
|
-
.replace(/'/g, '''); // Replace single quotes with HTML entity
|
|
1216
|
-
return `["${safeContent}"]`;
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
return match;
|
|
1220
|
-
});
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
// Enhanced auto-fixing for diamond nodes {...}
|
|
1224
|
-
if (trimmedLine.match(/\{[^{}]*\}/)) {
|
|
1225
|
-
modifiedLine = modifiedLine.replace(/\{([^{}]*)\}/g, (match, content) => {
|
|
1226
|
-
// Check if already properly quoted with outer quotes
|
|
1227
|
-
if (content.trim().startsWith('"') && content.trim().endsWith('"')) {
|
|
1228
|
-
// Extract the inner content (between the outer quotes)
|
|
1229
|
-
const innerContent = content.trim().slice(1, -1);
|
|
1230
|
-
// Check if inner content has unescaped quotes that need escaping
|
|
1231
|
-
if (innerContent.includes('"') || innerContent.includes("'")) {
|
|
1232
|
-
wasFixed = true;
|
|
1233
|
-
// Decode any existing HTML entities first, then re-encode ALL quotes
|
|
1234
|
-
const decodedContent = decodeHtmlEntities(innerContent);
|
|
1235
|
-
const safeContent = decodedContent
|
|
1236
|
-
.replace(/"/g, '"') // Replace ALL double quotes with HTML entity
|
|
1237
|
-
.replace(/'/g, '''); // Replace ALL single quotes with HTML entity
|
|
1238
|
-
return `{"${safeContent}"}`;
|
|
1239
|
-
}
|
|
1240
|
-
return match;
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
// Check if content needs quoting (contains problematic patterns)
|
|
1244
|
-
if (needsQuoting(content)) {
|
|
1245
|
-
wasFixed = true;
|
|
1246
|
-
// Use HTML entities for quotes as per Mermaid best practices:
|
|
1247
|
-
// - GitHub doesn't support single quotes in node labels (causes 'got PS' error)
|
|
1248
|
-
// - HTML entities are the official way to escape quotes in Mermaid
|
|
1249
|
-
// - Always use double quotes with curly brackets {"..."} for diamond nodes
|
|
1250
|
-
// IMPORTANT: Decode any existing HTML entities first to avoid double-encoding
|
|
1251
|
-
const decodedContent = decodeHtmlEntities(content);
|
|
1252
|
-
const safeContent = decodedContent
|
|
1253
|
-
.replace(/"/g, '"') // Replace double quotes with HTML entity
|
|
1254
|
-
.replace(/'/g, '''); // Replace single quotes with HTML entity
|
|
1255
|
-
return `{"${safeContent}"}`;
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
return match;
|
|
1259
|
-
});
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
return modifiedLine;
|
|
1263
|
-
});
|
|
1264
|
-
|
|
1265
|
-
if (wasFixed) {
|
|
1266
|
-
const fixedContent = fixedLines.join('\n');
|
|
1267
|
-
|
|
1268
|
-
// Replace the diagram in the response
|
|
1269
|
-
const attributesStr = diagram.attributes ? ` ${diagram.attributes}` : '';
|
|
1270
|
-
const newCodeBlock = `\`\`\`mermaid${attributesStr}\n${fixedContent}\n\`\`\``;
|
|
1271
|
-
|
|
1272
|
-
fixedResponse = fixedResponse.slice(0, diagram.startIndex) +
|
|
1273
|
-
newCodeBlock +
|
|
1274
|
-
fixedResponse.slice(diagram.endIndex);
|
|
1275
|
-
|
|
1041
|
+
for (const invalidDiagram of invalidDiagrams) {
|
|
1042
|
+
const originalContent = invalidDiagram.content;
|
|
1043
|
+
|
|
1044
|
+
// Try maid auto-fix
|
|
1045
|
+
const maidResult = await tryMaidAutoFix(originalContent, { debug });
|
|
1046
|
+
|
|
1047
|
+
if (maidResult.errors.length === 0) {
|
|
1048
|
+
// Maid fixed it completely
|
|
1049
|
+
const originalDiagram = diagrams[invalidDiagram.originalIndex];
|
|
1050
|
+
const attributesStr = originalDiagram.attributes ? ` ${originalDiagram.attributes}` : '';
|
|
1051
|
+
const newCodeBlock = `\`\`\`mermaid${attributesStr}\n${maidResult.fixed}\n\`\`\``;
|
|
1052
|
+
|
|
1053
|
+
fixedResponse = fixedResponse.slice(0, originalDiagram.startIndex) +
|
|
1054
|
+
newCodeBlock +
|
|
1055
|
+
fixedResponse.slice(originalDiagram.endIndex);
|
|
1056
|
+
|
|
1276
1057
|
fixingResults.push({
|
|
1277
|
-
diagramIndex:
|
|
1058
|
+
diagramIndex: invalidDiagram.originalIndex,
|
|
1278
1059
|
wasFixed: true,
|
|
1279
1060
|
originalContent: originalContent,
|
|
1280
|
-
fixedContent:
|
|
1281
|
-
originalError:
|
|
1282
|
-
|
|
1283
|
-
|
|
1061
|
+
fixedContent: maidResult.fixed,
|
|
1062
|
+
originalError: invalidDiagram.error,
|
|
1063
|
+
fixedWithMaid: true,
|
|
1064
|
+
fixLevel: maidResult.fixLevel
|
|
1284
1065
|
});
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
if (debug) {
|
|
1289
|
-
console.log(`[DEBUG] Mermaid validation: Proactively fixed diagram ${diagramIndex + 1} with node label quoting`);
|
|
1290
|
-
console.log(`[DEBUG] Mermaid validation: Applied automatic quoting to special characters`);
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
// If proactive fixes were applied, re-validate the entire response
|
|
1296
|
-
if (proactiveFixesApplied) {
|
|
1297
|
-
const revalidation = await validateMermaidResponse(fixedResponse);
|
|
1298
|
-
if (revalidation.isValid) {
|
|
1299
|
-
// All diagrams are now valid, return without AI fixing
|
|
1300
|
-
const totalTime = Date.now() - startTime;
|
|
1066
|
+
|
|
1067
|
+
maidFixesApplied = true;
|
|
1068
|
+
|
|
1301
1069
|
if (debug) {
|
|
1302
|
-
console.log(`[DEBUG] Mermaid validation:
|
|
1303
|
-
console.log(`[DEBUG] Mermaid validation: Applied ${fixingResults.length} proactive fixes`);
|
|
1304
|
-
}
|
|
1305
|
-
|
|
1306
|
-
// Record proactive fix success in telemetry
|
|
1307
|
-
if (tracer) {
|
|
1308
|
-
tracer.recordMermaidValidationEvent('proactive_fix_completed', {
|
|
1309
|
-
'mermaid_validation.success': true,
|
|
1310
|
-
'mermaid_validation.fix_method': 'node_label_quote_wrapping',
|
|
1311
|
-
'mermaid_validation.diagrams_fixed': fixingResults.length,
|
|
1312
|
-
'mermaid_validation.duration_ms': totalTime
|
|
1313
|
-
});
|
|
1070
|
+
console.log(`[DEBUG] Mermaid validation: Maid fixed diagram ${invalidDiagram.originalIndex + 1}`);
|
|
1314
1071
|
}
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
fixingResults: fixingResults,
|
|
1321
|
-
performanceMetrics: {
|
|
1322
|
-
totalTimeMs: totalTime,
|
|
1323
|
-
aiFixingTimeMs: 0,
|
|
1324
|
-
finalValidationTimeMs: 0,
|
|
1325
|
-
diagramsProcessed: fixingResults.length,
|
|
1326
|
-
diagramsFixed: fixingResults.length
|
|
1327
|
-
}
|
|
1328
|
-
};
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
|
|
1332
|
-
// Second pass: Try auto-fixing unquoted subgraph names with parentheses
|
|
1333
|
-
let subgraphFixesApplied = false;
|
|
1334
|
-
|
|
1335
|
-
// Re-extract diagrams and re-validate after HTML entity fixes
|
|
1336
|
-
const { diagrams: postHtmlDiagrams } = extractMermaidFromMarkdown(fixedResponse);
|
|
1337
|
-
const postHtmlValidation = await validateMermaidResponse(fixedResponse);
|
|
1338
|
-
|
|
1339
|
-
const stillInvalidAfterHtml = postHtmlValidation.diagrams
|
|
1340
|
-
.map((result, index) => ({ ...result, originalIndex: index }))
|
|
1341
|
-
.filter(result => !result.isValid)
|
|
1342
|
-
.reverse();
|
|
1072
|
+
} else if (maidResult.wasFixed) {
|
|
1073
|
+
// Maid improved it but didn't fix everything - update content for AI fixing
|
|
1074
|
+
const originalDiagram = diagrams[invalidDiagram.originalIndex];
|
|
1075
|
+
const attributesStr = originalDiagram.attributes ? ` ${originalDiagram.attributes}` : '';
|
|
1076
|
+
const newCodeBlock = `\`\`\`mermaid${attributesStr}\n${maidResult.fixed}\n\`\`\``;
|
|
1343
1077
|
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
// Extract the subgraph name part
|
|
1359
|
-
const match = trimmedLine.match(/^(\s*subgraph\s+)(.+)$/);
|
|
1360
|
-
if (match) {
|
|
1361
|
-
const prefix = match[1];
|
|
1362
|
-
const name = match[2];
|
|
1363
|
-
const fixedLine = line.replace(trimmedLine, `${prefix.trim()} "${name}"`);
|
|
1364
|
-
wasFixed = true;
|
|
1365
|
-
return fixedLine;
|
|
1366
|
-
}
|
|
1367
|
-
}
|
|
1368
|
-
return line;
|
|
1078
|
+
fixedResponse = fixedResponse.slice(0, originalDiagram.startIndex) +
|
|
1079
|
+
newCodeBlock +
|
|
1080
|
+
fixedResponse.slice(originalDiagram.endIndex);
|
|
1081
|
+
|
|
1082
|
+
fixingResults.push({
|
|
1083
|
+
diagramIndex: invalidDiagram.originalIndex,
|
|
1084
|
+
wasFixed: false,
|
|
1085
|
+
originalContent: originalContent,
|
|
1086
|
+
partiallyFixedContent: maidResult.fixed,
|
|
1087
|
+
originalError: invalidDiagram.error,
|
|
1088
|
+
remainingErrors: maidResult.errors,
|
|
1089
|
+
fixedWithMaid: 'partial',
|
|
1090
|
+
fixLevel: maidResult.fixLevel
|
|
1369
1091
|
});
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
// Validate the fixed content
|
|
1375
|
-
try {
|
|
1376
|
-
const quickValidation = await validateMermaidDiagram(fixedContent);
|
|
1377
|
-
if (quickValidation.isValid) {
|
|
1378
|
-
// Subgraph auto-fix worked!
|
|
1379
|
-
const originalDiagram = postHtmlDiagrams[invalidDiagram.originalIndex];
|
|
1380
|
-
const attributesStr = originalDiagram.attributes ? ` ${originalDiagram.attributes}` : '';
|
|
1381
|
-
const newCodeBlock = `\`\`\`mermaid${attributesStr}\n${fixedContent}\n\`\`\``;
|
|
1382
|
-
|
|
1383
|
-
fixedResponse = fixedResponse.slice(0, originalDiagram.startIndex) +
|
|
1384
|
-
newCodeBlock +
|
|
1385
|
-
fixedResponse.slice(originalDiagram.endIndex);
|
|
1386
|
-
|
|
1387
|
-
fixingResults.push({
|
|
1388
|
-
originalIndex: invalidDiagram.originalIndex,
|
|
1389
|
-
wasFixed: true,
|
|
1390
|
-
originalError: invalidDiagram.error,
|
|
1391
|
-
fixMethod: 'subgraph_quote_wrapping',
|
|
1392
|
-
fixedWithSubgraphQuoting: true
|
|
1393
|
-
});
|
|
1394
|
-
|
|
1395
|
-
subgraphFixesApplied = true;
|
|
1396
|
-
|
|
1397
|
-
if (debug) {
|
|
1398
|
-
console.log(`[DEBUG] Mermaid validation: Fixed diagram ${invalidDiagram.originalIndex + 1} with subgraph quote wrapping`);
|
|
1399
|
-
console.log(`[DEBUG] Mermaid validation: Original error: ${invalidDiagram.error}`);
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
} catch (error) {
|
|
1403
|
-
if (debug) {
|
|
1404
|
-
console.log(`[DEBUG] Mermaid validation: Subgraph auto-fix didn't work for diagram ${invalidDiagram.originalIndex + 1}: ${error.message}`);
|
|
1405
|
-
}
|
|
1406
|
-
}
|
|
1407
|
-
}
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
// If subgraph fixes were applied, re-validate the entire response
|
|
1412
|
-
if (subgraphFixesApplied) {
|
|
1413
|
-
const revalidation = await validateMermaidResponse(fixedResponse);
|
|
1414
|
-
if (revalidation.isValid) {
|
|
1415
|
-
// All diagrams are now valid, return without AI fixing
|
|
1416
|
-
const totalTime = Date.now() - startTime;
|
|
1092
|
+
|
|
1093
|
+
maidFixesApplied = true;
|
|
1094
|
+
|
|
1417
1095
|
if (debug) {
|
|
1418
|
-
console.log(`[DEBUG] Mermaid validation:
|
|
1419
|
-
console.log(`[DEBUG] Mermaid validation: Applied ${fixingResults.length} auto-fixes (HTML entities + subgraph quotes)`);
|
|
1420
|
-
}
|
|
1421
|
-
|
|
1422
|
-
// Record auto-fix success in telemetry
|
|
1423
|
-
if (tracer) {
|
|
1424
|
-
tracer.recordMermaidValidationEvent('auto_fix_completed', {
|
|
1425
|
-
'mermaid_validation.success': true,
|
|
1426
|
-
'mermaid_validation.fix_method': 'auto_fixes',
|
|
1427
|
-
'mermaid_validation.diagrams_fixed': fixingResults.length,
|
|
1428
|
-
'mermaid_validation.duration_ms': totalTime
|
|
1429
|
-
});
|
|
1096
|
+
console.log(`[DEBUG] Mermaid validation: Maid partially fixed diagram ${invalidDiagram.originalIndex + 1}, ${maidResult.errors.length} errors remain`);
|
|
1430
1097
|
}
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
diagramsProcessed: fixingResults.length,
|
|
1442
|
-
diagramsFixed: fixingResults.length
|
|
1443
|
-
}
|
|
1444
|
-
};
|
|
1098
|
+
} else {
|
|
1099
|
+
// Maid couldn't fix it, keep track for AI fixing
|
|
1100
|
+
fixingResults.push({
|
|
1101
|
+
diagramIndex: invalidDiagram.originalIndex,
|
|
1102
|
+
wasFixed: false,
|
|
1103
|
+
originalContent: originalContent,
|
|
1104
|
+
originalError: invalidDiagram.error,
|
|
1105
|
+
maidErrors: maidResult.errors,
|
|
1106
|
+
fixedWithMaid: false
|
|
1107
|
+
});
|
|
1445
1108
|
}
|
|
1446
1109
|
}
|
|
1447
|
-
|
|
1448
|
-
// Third pass: Try auto-fixing node labels with parentheses or single quotes
|
|
1449
|
-
let nodeLabelFixesApplied = false;
|
|
1450
|
-
|
|
1451
|
-
// Re-extract diagrams and re-validate after previous fixes
|
|
1452
|
-
const { diagrams: postSubgraphDiagrams } = extractMermaidFromMarkdown(fixedResponse);
|
|
1453
|
-
const postSubgraphValidation = await validateMermaidResponse(fixedResponse);
|
|
1454
|
-
|
|
1455
|
-
const stillInvalidAfterSubgraph = postSubgraphValidation.diagrams
|
|
1456
|
-
.map((result, index) => ({ ...result, originalIndex: index }))
|
|
1457
|
-
.filter(result => !result.isValid)
|
|
1458
|
-
.reverse();
|
|
1459
1110
|
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
// Enhanced auto-fixing for square bracket nodes [...]
|
|
1477
|
-
// Look for any node labels that contain special characters and aren't already quoted
|
|
1478
|
-
if (trimmedLine.match(/\[[^\]]*\]/)) {
|
|
1479
|
-
modifiedLine = modifiedLine.replace(/\[([^\]]*)\]/g, (match, content) => {
|
|
1480
|
-
// Check if already properly quoted with outer quotes
|
|
1481
|
-
if (content.trim().startsWith('"') && content.trim().endsWith('"')) {
|
|
1482
|
-
// Extract the inner content (between the outer quotes)
|
|
1483
|
-
const innerContent = content.trim().slice(1, -1);
|
|
1484
|
-
// Check if inner content has unescaped quotes that need escaping
|
|
1485
|
-
if (innerContent.includes('"') || innerContent.includes("'")) {
|
|
1486
|
-
wasFixed = true;
|
|
1487
|
-
// Decode any existing HTML entities first, then re-encode ALL quotes
|
|
1488
|
-
const decodedContent = decodeHtmlEntities(innerContent);
|
|
1489
|
-
const safeContent = decodedContent
|
|
1490
|
-
.replace(/"/g, '"') // Replace ALL double quotes with HTML entity
|
|
1491
|
-
.replace(/'/g, '''); // Replace ALL single quotes with HTML entity
|
|
1492
|
-
return `["${safeContent}"]`;
|
|
1493
|
-
}
|
|
1494
|
-
return match;
|
|
1495
|
-
}
|
|
1496
|
-
|
|
1497
|
-
// Check if content needs quoting (contains problematic patterns)
|
|
1498
|
-
if (needsQuoting(content)) {
|
|
1499
|
-
wasFixed = true;
|
|
1500
|
-
// Use HTML entities for quotes as per Mermaid best practices:
|
|
1501
|
-
// - GitHub doesn't support single quotes in node labels (causes 'got PS' error)
|
|
1502
|
-
// - HTML entities are the official way to escape quotes in Mermaid
|
|
1503
|
-
// - Always use double quotes with square brackets ["..."] for node labels
|
|
1504
|
-
// IMPORTANT: Decode any existing HTML entities first to avoid double-encoding
|
|
1505
|
-
const decodedContent = decodeHtmlEntities(content);
|
|
1506
|
-
const safeContent = decodedContent
|
|
1507
|
-
.replace(/"/g, '"') // Replace double quotes with HTML entity
|
|
1508
|
-
.replace(/'/g, '''); // Replace single quotes with HTML entity
|
|
1509
|
-
return `["${safeContent}"]`;
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
|
-
return match;
|
|
1513
|
-
});
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
// Enhanced auto-fixing for diamond nodes {...}
|
|
1517
|
-
if (trimmedLine.match(/\{[^{}]*\}/)) {
|
|
1518
|
-
modifiedLine = modifiedLine.replace(/\{([^{}]*)\}/g, (match, content) => {
|
|
1519
|
-
// Check if already properly quoted with outer quotes
|
|
1520
|
-
if (content.trim().startsWith('"') && content.trim().endsWith('"')) {
|
|
1521
|
-
// Extract the inner content (between the outer quotes)
|
|
1522
|
-
const innerContent = content.trim().slice(1, -1);
|
|
1523
|
-
// Check if inner content has unescaped quotes that need escaping
|
|
1524
|
-
if (innerContent.includes('"') || innerContent.includes("'")) {
|
|
1525
|
-
wasFixed = true;
|
|
1526
|
-
// Decode any existing HTML entities first, then re-encode ALL quotes
|
|
1527
|
-
const decodedContent = decodeHtmlEntities(innerContent);
|
|
1528
|
-
const safeContent = decodedContent
|
|
1529
|
-
.replace(/"/g, '"') // Replace ALL double quotes with HTML entity
|
|
1530
|
-
.replace(/'/g, '''); // Replace ALL single quotes with HTML entity
|
|
1531
|
-
return `{"${safeContent}"}`;
|
|
1532
|
-
}
|
|
1533
|
-
return match;
|
|
1534
|
-
}
|
|
1535
|
-
|
|
1536
|
-
// Check if content needs quoting (contains problematic patterns)
|
|
1537
|
-
if (needsQuoting(content)) {
|
|
1538
|
-
wasFixed = true;
|
|
1539
|
-
// Use HTML entities for quotes as per Mermaid best practices:
|
|
1540
|
-
// - GitHub doesn't support single quotes in node labels (causes 'got PS' error)
|
|
1541
|
-
// - HTML entities are the official way to escape quotes in Mermaid
|
|
1542
|
-
// - Always use double quotes with curly brackets {"..."} for diamond nodes
|
|
1543
|
-
// IMPORTANT: Decode any existing HTML entities first to avoid double-encoding
|
|
1544
|
-
const decodedContent = decodeHtmlEntities(content);
|
|
1545
|
-
const safeContent = decodedContent
|
|
1546
|
-
.replace(/"/g, '"') // Replace double quotes with HTML entity
|
|
1547
|
-
.replace(/'/g, '''); // Replace single quotes with HTML entity
|
|
1548
|
-
return `{"${safeContent}"}`;
|
|
1549
|
-
}
|
|
1550
|
-
|
|
1551
|
-
return match;
|
|
1552
|
-
});
|
|
1553
|
-
}
|
|
1554
|
-
|
|
1555
|
-
return modifiedLine;
|
|
1111
|
+
// Re-validate after maid fixes
|
|
1112
|
+
const revalidation = await validateMermaidResponse(fixedResponse);
|
|
1113
|
+
if (revalidation.isValid) {
|
|
1114
|
+
// All diagrams fixed with maid
|
|
1115
|
+
const totalTime = Date.now() - startTime;
|
|
1116
|
+
if (debug) {
|
|
1117
|
+
console.log(`[DEBUG] Mermaid validation: All diagrams fixed with maid in ${totalTime}ms, no AI needed`);
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
if (tracer) {
|
|
1121
|
+
tracer.recordMermaidValidationEvent('maid_fix_completed', {
|
|
1122
|
+
'mermaid_validation.success': true,
|
|
1123
|
+
'mermaid_validation.fix_method': 'maid',
|
|
1124
|
+
'mermaid_validation.diagrams_fixed': fixingResults.filter(r => r.wasFixed).length,
|
|
1125
|
+
'mermaid_validation.duration_ms': totalTime
|
|
1556
1126
|
});
|
|
1557
|
-
|
|
1558
|
-
if (wasFixed) {
|
|
1559
|
-
const fixedContent = fixedLines.join('\n');
|
|
1560
|
-
|
|
1561
|
-
// Validate the fixed content
|
|
1562
|
-
try {
|
|
1563
|
-
const quickValidation = await validateMermaidDiagram(fixedContent);
|
|
1564
|
-
if (quickValidation.isValid) {
|
|
1565
|
-
// Node label auto-fix worked!
|
|
1566
|
-
const originalDiagram = postSubgraphDiagrams[invalidDiagram.originalIndex];
|
|
1567
|
-
const attributesStr = originalDiagram.attributes ? ` ${originalDiagram.attributes}` : '';
|
|
1568
|
-
const newCodeBlock = `\`\`\`mermaid${attributesStr}\n${fixedContent}\n\`\`\``;
|
|
1569
|
-
|
|
1570
|
-
fixedResponse = fixedResponse.slice(0, originalDiagram.startIndex) +
|
|
1571
|
-
newCodeBlock +
|
|
1572
|
-
fixedResponse.slice(originalDiagram.endIndex);
|
|
1573
|
-
|
|
1574
|
-
fixingResults.push({
|
|
1575
|
-
originalIndex: invalidDiagram.originalIndex,
|
|
1576
|
-
wasFixed: true,
|
|
1577
|
-
originalError: invalidDiagram.error,
|
|
1578
|
-
fixMethod: 'node_label_quote_wrapping',
|
|
1579
|
-
fixedWithNodeLabelQuoting: true
|
|
1580
|
-
});
|
|
1581
|
-
|
|
1582
|
-
nodeLabelFixesApplied = true;
|
|
1583
|
-
|
|
1584
|
-
if (debug) {
|
|
1585
|
-
console.log(`[DEBUG] Mermaid validation: Fixed diagram ${invalidDiagram.originalIndex + 1} with node label quote wrapping`);
|
|
1586
|
-
console.log(`[DEBUG] Mermaid validation: Original error: ${invalidDiagram.error}`);
|
|
1587
|
-
}
|
|
1588
|
-
}
|
|
1589
|
-
} catch (error) {
|
|
1590
|
-
if (debug) {
|
|
1591
|
-
console.log(`[DEBUG] Mermaid validation: Node label auto-fix didn't work for diagram ${invalidDiagram.originalIndex + 1}: ${error.message}`);
|
|
1592
|
-
}
|
|
1593
|
-
}
|
|
1594
|
-
}
|
|
1595
1127
|
}
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
// Record auto-fix success in telemetry
|
|
1610
|
-
if (tracer) {
|
|
1611
|
-
tracer.recordMermaidValidationEvent('auto_fix_completed', {
|
|
1612
|
-
'mermaid_validation.success': true,
|
|
1613
|
-
'mermaid_validation.fix_method': 'auto_fixes',
|
|
1614
|
-
'mermaid_validation.diagrams_fixed': fixingResults.length,
|
|
1615
|
-
'mermaid_validation.duration_ms': totalTime
|
|
1616
|
-
});
|
|
1128
|
+
|
|
1129
|
+
return {
|
|
1130
|
+
...revalidation,
|
|
1131
|
+
wasFixed: true,
|
|
1132
|
+
originalResponse: response,
|
|
1133
|
+
fixedResponse: fixedResponse,
|
|
1134
|
+
fixingResults: fixingResults,
|
|
1135
|
+
performanceMetrics: {
|
|
1136
|
+
totalTimeMs: totalTime,
|
|
1137
|
+
aiFixingTimeMs: 0,
|
|
1138
|
+
diagramsProcessed: fixingResults.length,
|
|
1139
|
+
diagramsFixed: fixingResults.filter(r => r.wasFixed).length
|
|
1617
1140
|
}
|
|
1618
|
-
|
|
1619
|
-
...revalidation,
|
|
1620
|
-
wasFixed: true,
|
|
1621
|
-
originalResponse: response,
|
|
1622
|
-
fixedResponse: fixedResponse,
|
|
1623
|
-
fixingResults: fixingResults,
|
|
1624
|
-
performanceMetrics: {
|
|
1625
|
-
totalTimeMs: totalTime,
|
|
1626
|
-
aiFixingTimeMs: 0,
|
|
1627
|
-
finalValidationTimeMs: 0,
|
|
1628
|
-
diagramsProcessed: fixingResults.length,
|
|
1629
|
-
diagramsFixed: fixingResults.length
|
|
1630
|
-
}
|
|
1631
|
-
};
|
|
1632
|
-
}
|
|
1633
|
-
}
|
|
1634
|
-
|
|
1635
|
-
// Re-extract diagrams and re-validate after HTML entity fixes
|
|
1636
|
-
const { diagrams: updatedDiagrams } = extractMermaidFromMarkdown(fixedResponse);
|
|
1637
|
-
const updatedValidation = await validateMermaidResponse(fixedResponse);
|
|
1638
|
-
|
|
1639
|
-
// Still have invalid diagrams after all auto-fixes, proceed with AI fixing
|
|
1640
|
-
if (debug) {
|
|
1641
|
-
const stillInvalidAfterHtml = updatedValidation?.diagrams?.filter(d => !d.isValid)?.length || invalidCount;
|
|
1642
|
-
console.log(`[DEBUG] Mermaid validation: ${stillInvalidAfterHtml} diagrams still invalid after HTML entity decoding, starting AI fixing...`);
|
|
1643
|
-
console.log(`[DEBUG] Mermaid validation: HTML entity fixes applied: ${fixingResults.length}`);
|
|
1141
|
+
};
|
|
1644
1142
|
}
|
|
1645
|
-
|
|
1646
|
-
//
|
|
1143
|
+
|
|
1144
|
+
// Still have invalid diagrams, proceed with AI fixing
|
|
1647
1145
|
if (debug) {
|
|
1648
|
-
|
|
1146
|
+
const stillInvalid = revalidation.diagrams.filter(d => !d.isValid).length;
|
|
1147
|
+
console.log(`[DEBUG] Mermaid validation: ${stillInvalid} diagrams still invalid after maid, starting AI fixing...`);
|
|
1649
1148
|
}
|
|
1149
|
+
|
|
1650
1150
|
const aiFixingStart = Date.now();
|
|
1651
1151
|
const mermaidFixer = new MermaidFixingAgent({
|
|
1652
1152
|
path, provider, model, debug, tracer
|
|
1653
1153
|
});
|
|
1654
|
-
|
|
1655
|
-
|
|
1154
|
+
|
|
1155
|
+
// Extract updated diagrams and validation
|
|
1156
|
+
const { diagrams: updatedDiagrams } = extractMermaidFromMarkdown(fixedResponse);
|
|
1157
|
+
const stillInvalidDiagrams = revalidation.diagrams
|
|
1656
1158
|
.map((result, index) => ({ ...result, originalIndex: index }))
|
|
1657
1159
|
.filter(result => !result.isValid)
|
|
1658
1160
|
.reverse();
|
|
1659
|
-
|
|
1161
|
+
|
|
1660
1162
|
if (debug) {
|
|
1661
1163
|
console.log(`[DEBUG] Mermaid validation: Found ${stillInvalidDiagrams.length} diagrams requiring AI fixing`);
|
|
1662
1164
|
}
|
|
@@ -1664,15 +1166,18 @@ export async function validateAndFixMermaidResponse(response, options = {}) {
|
|
|
1664
1166
|
for (const invalidDiagram of stillInvalidDiagrams) {
|
|
1665
1167
|
if (debug) {
|
|
1666
1168
|
console.log(`[DEBUG] Mermaid validation: Attempting AI fix for diagram ${invalidDiagram.originalIndex + 1}`);
|
|
1667
|
-
console.log(`[DEBUG] Mermaid validation: Diagram type: ${invalidDiagram.diagramType || 'unknown'}`);
|
|
1668
|
-
console.log(`[DEBUG] Mermaid validation: Error to fix: ${invalidDiagram.error}`);
|
|
1669
1169
|
}
|
|
1670
|
-
|
|
1170
|
+
|
|
1671
1171
|
const diagramFixStart = Date.now();
|
|
1672
1172
|
try {
|
|
1173
|
+
// Pass maid's structured errors if available
|
|
1174
|
+
const errorsToPass = invalidDiagram.errors && invalidDiagram.errors.length > 0
|
|
1175
|
+
? invalidDiagram.errors
|
|
1176
|
+
: [invalidDiagram.error];
|
|
1177
|
+
|
|
1673
1178
|
const fixedContent = await mermaidFixer.fixMermaidDiagram(
|
|
1674
1179
|
invalidDiagram.content,
|
|
1675
|
-
|
|
1180
|
+
errorsToPass,
|
|
1676
1181
|
{ diagramType: invalidDiagram.diagramType }
|
|
1677
1182
|
);
|
|
1678
1183
|
const diagramFixTime = Date.now() - diagramFixStart;
|
|
@@ -1682,91 +1187,68 @@ export async function validateAndFixMermaidResponse(response, options = {}) {
|
|
|
1682
1187
|
const originalDiagram = updatedDiagrams[invalidDiagram.originalIndex];
|
|
1683
1188
|
const attributesStr = originalDiagram.attributes ? ` ${originalDiagram.attributes}` : '';
|
|
1684
1189
|
const newCodeBlock = `\`\`\`mermaid${attributesStr}\n${fixedContent}\n\`\`\``;
|
|
1685
|
-
|
|
1686
|
-
fixedResponse = fixedResponse.slice(0, originalDiagram.startIndex) +
|
|
1687
|
-
newCodeBlock +
|
|
1190
|
+
|
|
1191
|
+
fixedResponse = fixedResponse.slice(0, originalDiagram.startIndex) +
|
|
1192
|
+
newCodeBlock +
|
|
1688
1193
|
fixedResponse.slice(originalDiagram.endIndex);
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1194
|
+
|
|
1195
|
+
// Find existing result or create new one
|
|
1196
|
+
const existingResultIndex = fixingResults.findIndex(r => r.diagramIndex === invalidDiagram.originalIndex);
|
|
1197
|
+
if (existingResultIndex >= 0) {
|
|
1198
|
+
fixingResults[existingResultIndex] = {
|
|
1199
|
+
...fixingResults[existingResultIndex],
|
|
1200
|
+
wasFixed: true,
|
|
1201
|
+
fixedContent: fixedContent,
|
|
1202
|
+
aiFixingTimeMs: diagramFixTime
|
|
1203
|
+
};
|
|
1204
|
+
} else {
|
|
1205
|
+
fixingResults.push({
|
|
1206
|
+
diagramIndex: invalidDiagram.originalIndex,
|
|
1207
|
+
wasFixed: true,
|
|
1208
|
+
originalContent: invalidDiagram.content,
|
|
1209
|
+
fixedContent: fixedContent,
|
|
1210
|
+
originalError: invalidDiagram.error,
|
|
1211
|
+
aiFixingTimeMs: diagramFixTime
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1698
1214
|
|
|
1699
1215
|
if (debug) {
|
|
1700
|
-
console.log(`[DEBUG] Mermaid validation: Successfully fixed diagram ${invalidDiagram.originalIndex + 1} in ${diagramFixTime}ms`);
|
|
1701
|
-
console.log(`[DEBUG] Mermaid validation: Original error: ${invalidDiagram.error}`);
|
|
1702
|
-
console.log(`[DEBUG] Mermaid validation: Content changes: ${invalidDiagram.content.length} -> ${fixedContent.length} chars`);
|
|
1216
|
+
console.log(`[DEBUG] Mermaid validation: Successfully fixed diagram ${invalidDiagram.originalIndex + 1} with AI in ${diagramFixTime}ms`);
|
|
1703
1217
|
}
|
|
1704
1218
|
} else {
|
|
1705
|
-
fixingResults.push({
|
|
1706
|
-
diagramIndex: invalidDiagram.originalIndex,
|
|
1707
|
-
wasFixed: false,
|
|
1708
|
-
originalContent: invalidDiagram.content,
|
|
1709
|
-
originalError: invalidDiagram.error,
|
|
1710
|
-
fixingError: 'No valid fix generated',
|
|
1711
|
-
aiFixingTimeMs: diagramFixTime
|
|
1712
|
-
});
|
|
1713
|
-
|
|
1714
1219
|
if (debug) {
|
|
1715
1220
|
console.log(`[DEBUG] Mermaid validation: AI fix failed for diagram ${invalidDiagram.originalIndex + 1} - no valid fix generated`);
|
|
1716
1221
|
}
|
|
1717
1222
|
}
|
|
1718
1223
|
} catch (error) {
|
|
1719
|
-
const diagramFixTime = Date.now() - diagramFixStart;
|
|
1720
|
-
fixingResults.push({
|
|
1721
|
-
diagramIndex: invalidDiagram.originalIndex,
|
|
1722
|
-
wasFixed: false,
|
|
1723
|
-
originalContent: invalidDiagram.content,
|
|
1724
|
-
originalError: invalidDiagram.error,
|
|
1725
|
-
fixingError: error.message,
|
|
1726
|
-
aiFixingTimeMs: diagramFixTime
|
|
1727
|
-
});
|
|
1728
|
-
|
|
1729
1224
|
if (debug) {
|
|
1730
|
-
console.log(`[DEBUG] Mermaid validation: AI fix failed for diagram ${invalidDiagram.originalIndex + 1}
|
|
1225
|
+
console.log(`[DEBUG] Mermaid validation: AI fix failed for diagram ${invalidDiagram.originalIndex + 1}: ${error.message}`);
|
|
1731
1226
|
}
|
|
1732
1227
|
}
|
|
1733
1228
|
}
|
|
1734
1229
|
|
|
1735
|
-
//
|
|
1736
|
-
const finalValidationStart = Date.now();
|
|
1230
|
+
// Final validation
|
|
1737
1231
|
const finalValidation = await validateMermaidResponse(fixedResponse);
|
|
1738
|
-
const finalValidationTime = Date.now() - finalValidationStart;
|
|
1739
1232
|
const totalTime = Date.now() - startTime;
|
|
1740
1233
|
const aiFixingTime = Date.now() - aiFixingStart;
|
|
1741
1234
|
|
|
1742
|
-
// Check if any diagrams were actually fixed
|
|
1743
1235
|
const wasActuallyFixed = fixingResults.some(result => result.wasFixed);
|
|
1744
1236
|
const fixedCount = fixingResults.filter(result => result.wasFixed).length;
|
|
1745
|
-
const totalAttempts = fixingResults.length;
|
|
1746
1237
|
|
|
1747
1238
|
if (debug) {
|
|
1748
|
-
console.log(`[DEBUG] Mermaid validation: Final validation completed in ${finalValidationTime}ms`);
|
|
1749
1239
|
console.log(`[DEBUG] Mermaid validation: Total process time: ${totalTime}ms (AI fixing: ${aiFixingTime}ms)`);
|
|
1750
|
-
console.log(`[DEBUG] Mermaid validation: Fixed ${fixedCount}/${
|
|
1240
|
+
console.log(`[DEBUG] Mermaid validation: Fixed ${fixedCount}/${fixingResults.length} diagrams`);
|
|
1751
1241
|
console.log(`[DEBUG] Mermaid validation: Final result - all valid: ${finalValidation.isValid}`);
|
|
1752
|
-
|
|
1753
|
-
if (mermaidFixer.getTokenUsage) {
|
|
1754
|
-
const tokenUsage = mermaidFixer.getTokenUsage();
|
|
1755
|
-
console.log(`[DEBUG] Mermaid validation: AI token usage - prompt: ${tokenUsage?.promptTokens || 0}, completion: ${tokenUsage?.completionTokens || 0}`);
|
|
1756
|
-
}
|
|
1757
1242
|
}
|
|
1758
|
-
|
|
1759
|
-
// Record final completion in telemetry
|
|
1243
|
+
|
|
1760
1244
|
if (tracer) {
|
|
1761
1245
|
tracer.recordMermaidValidationEvent('completed', {
|
|
1762
1246
|
'mermaid_validation.success': finalValidation.isValid,
|
|
1763
1247
|
'mermaid_validation.was_fixed': wasActuallyFixed,
|
|
1764
|
-
'mermaid_validation.diagrams_processed':
|
|
1248
|
+
'mermaid_validation.diagrams_processed': fixingResults.length,
|
|
1765
1249
|
'mermaid_validation.diagrams_fixed': fixedCount,
|
|
1766
1250
|
'mermaid_validation.total_duration_ms': totalTime,
|
|
1767
|
-
'mermaid_validation.ai_fixing_duration_ms': aiFixingTime
|
|
1768
|
-
'mermaid_validation.final_validation_duration_ms': finalValidationTime,
|
|
1769
|
-
'mermaid_validation.token_usage': mermaidFixer.getTokenUsage ? mermaidFixer.getTokenUsage() : null
|
|
1251
|
+
'mermaid_validation.ai_fixing_duration_ms': aiFixingTime
|
|
1770
1252
|
});
|
|
1771
1253
|
}
|
|
1772
1254
|
|
|
@@ -1779,8 +1261,7 @@ export async function validateAndFixMermaidResponse(response, options = {}) {
|
|
|
1779
1261
|
performanceMetrics: {
|
|
1780
1262
|
totalTimeMs: totalTime,
|
|
1781
1263
|
aiFixingTimeMs: aiFixingTime,
|
|
1782
|
-
|
|
1783
|
-
diagramsProcessed: totalAttempts,
|
|
1264
|
+
diagramsProcessed: fixingResults.length,
|
|
1784
1265
|
diagramsFixed: fixedCount
|
|
1785
1266
|
},
|
|
1786
1267
|
tokenUsage: mermaidFixer.getTokenUsage()
|
|
@@ -1788,10 +1269,9 @@ export async function validateAndFixMermaidResponse(response, options = {}) {
|
|
|
1788
1269
|
|
|
1789
1270
|
} catch (error) {
|
|
1790
1271
|
if (debug) {
|
|
1791
|
-
console.error(`[DEBUG] Mermaid fixing
|
|
1272
|
+
console.error(`[DEBUG] Mermaid fixing failed: ${error.message}`);
|
|
1792
1273
|
}
|
|
1793
1274
|
|
|
1794
|
-
// Return original validation with fixing error
|
|
1795
1275
|
return {
|
|
1796
1276
|
...validation,
|
|
1797
1277
|
wasFixed: false,
|
|
@@ -1800,4 +1280,4 @@ export async function validateAndFixMermaidResponse(response, options = {}) {
|
|
|
1800
1280
|
fixingError: error.message
|
|
1801
1281
|
};
|
|
1802
1282
|
}
|
|
1803
|
-
}
|
|
1283
|
+
}
|