Skip to content

Commit 22d4d3b

Browse files
Terraphim CIclaude
andcommitted
fix(agent-workflows): replace parallelization mock data with real LLM output
generatePerspectiveAnalysis() and generateAggregatedInsights() were returning hardcoded mock data, ignoring actual API responses. Now parses LLM markdown from parallel_tasks[].result into structured UI components (title, keyPoints, insights, recommendations, confidence). Co-Authored-By: Terraphim AI <noreply@anthropic.com>
1 parent 8810428 commit 22d4d3b

1 file changed

Lines changed: 172 additions & 125 deletions

File tree

  • examples/agent-workflows/3-parallelization

examples/agent-workflows/3-parallelization/app.js

Lines changed: 172 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -490,112 +490,126 @@ class ParallelizationAnalysisDemo {
490490
}
491491

492492
generatePerspectiveAnalysis(perspective, topic, result) {
493-
// Generate mock analysis based on perspective characteristics
494-
const analyses = {
495-
analytical: (topic) => ({
496-
title: 'Data-Driven Analysis',
497-
keyPoints: [
498-
'Market research indicates significant growth potential',
499-
'Statistical trends show 40% year-over-year increases',
500-
'Quantitative models predict positive ROI within 18 months',
501-
'Benchmark analysis reveals competitive advantages'
502-
],
503-
insights: 'Evidence-based evaluation shows strong fundamentals with measurable success metrics.',
504-
recommendations: [
505-
'Implement robust analytics tracking',
506-
'Establish KPI baselines and monitoring',
507-
'Conduct A/B testing for optimization'
508-
],
509-
confidence: 0.85
510-
}),
511-
512-
creative: (topic) => ({
513-
title: 'Innovative Exploration',
514-
keyPoints: [
515-
'Blue ocean opportunities in emerging markets',
516-
'Disruptive potential through novel approaches',
517-
'Cross-industry inspiration from unexpected sources',
518-
'Future-forward thinking beyond current paradigms'
519-
],
520-
insights: 'Innovative approaches could revolutionize the traditional landscape and create new value propositions.',
521-
recommendations: [
522-
'Prototype unconventional solutions',
523-
'Explore adjacent market opportunities',
524-
'Foster innovation through experimentation'
525-
],
526-
confidence: 0.78
527-
}),
528-
529-
practical: (topic) => ({
530-
title: 'Implementation Focus',
531-
keyPoints: [
532-
'Clear roadmap with achievable milestones',
533-
'Resource requirements are manageable',
534-
'Technical feasibility confirmed by experts',
535-
'Operational processes can scale effectively'
536-
],
537-
insights: 'Practical implementation is feasible with proper planning and resource allocation.',
538-
recommendations: [
539-
'Develop phased rollout strategy',
540-
'Allocate adequate resources and timeline',
541-
'Establish clear success criteria'
542-
],
543-
confidence: 0.92
544-
}),
545-
546-
critical: (topic) => ({
547-
title: 'Risk Assessment',
548-
keyPoints: [
549-
'Market volatility poses significant challenges',
550-
'Regulatory compliance requires careful attention',
551-
'Competitive responses could erode advantages',
552-
'Technical dependencies create vulnerability'
553-
],
554-
insights: 'Several critical risks must be mitigated before proceeding with full implementation.',
555-
recommendations: [
556-
'Develop comprehensive risk mitigation plan',
557-
'Establish contingency strategies',
558-
'Monitor regulatory changes closely'
559-
],
560-
confidence: 0.88
561-
}),
562-
563-
strategic: (topic) => ({
564-
title: 'Long-term Strategy',
565-
keyPoints: [
566-
'Aligns with 5-year organizational vision',
567-
'Creates sustainable competitive moats',
568-
'Positions for future market expansion',
569-
'Builds platform for additional opportunities'
570-
],
571-
insights: 'Strategic positioning provides long-term value creation and competitive advantage.',
572-
recommendations: [
573-
'Integrate with broader strategic initiatives',
574-
'Build capabilities for future expansion',
575-
'Establish strategic partnerships'
576-
],
577-
confidence: 0.89
578-
}),
579-
580-
user_centered: (topic) => ({
581-
title: 'Human Impact Analysis',
582-
keyPoints: [
583-
'Significant positive impact on user experience',
584-
'Accessibility considerations well-addressed',
585-
'Stakeholder feedback overwhelmingly positive',
586-
'Social impact creates meaningful value'
587-
],
588-
insights: 'Human-centered approach ensures widespread adoption and positive societal impact.',
589-
recommendations: [
590-
'Prioritize user feedback in development',
591-
'Ensure accessibility across all features',
592-
'Measure and optimize user satisfaction'
593-
],
594-
confidence: 0.91
595-
})
596-
};
493+
// Extract real LLM content from the API response
494+
const perspectiveId = perspective.id;
495+
496+
// Find matching task from parallel_tasks array
497+
let taskResult = null;
498+
if (result && result.result && Array.isArray(result.result.parallel_tasks)) {
499+
taskResult = result.result.parallel_tasks.find(t => t.perspective === perspectiveId);
500+
// Fallback: match by index if perspective field doesn't match
501+
if (!taskResult) {
502+
taskResult = result.result.parallel_tasks[0];
503+
}
504+
}
505+
506+
const llmText = taskResult ? taskResult.result : (result && result.result && result.result.aggregated_result) || '';
507+
508+
if (!llmText) {
509+
// Fallback if no LLM result available
510+
return {
511+
title: `${perspective.name} Analysis`,
512+
keyPoints: ['No analysis content received from server'],
513+
insights: 'The API call completed but returned no content for this perspective.',
514+
recommendations: ['Try again or check server logs'],
515+
confidence: 0
516+
};
517+
}
597518

598-
return (analyses[perspective.id] && analyses[perspective.id](topic)) || analyses.analytical(topic);
519+
// Parse the LLM markdown into structured analysis
520+
return this.parseLlmResponse(perspective, llmText);
521+
}
522+
523+
parseLlmResponse(perspective, text) {
524+
// Extract sections from LLM markdown response
525+
const lines = text.split('\n').filter(l => l.trim());
526+
527+
// Extract title from first heading or first bold line
528+
let title = `${perspective.name} Analysis`;
529+
for (const line of lines) {
530+
const headingMatch = line.match(/^\*\*(.+?)\*\*$/) || line.match(/^#+\s+(.+)/);
531+
if (headingMatch) {
532+
title = headingMatch[1].replace(/\*\*/g, '');
533+
break;
534+
}
535+
}
536+
537+
// Extract bullet points as key points (first 6)
538+
const keyPoints = [];
539+
for (const line of lines) {
540+
const bulletMatch = line.match(/^\s*[-*]\s+\*\*(.+?)\*\*[:\s]*(.*)/);
541+
if (bulletMatch) {
542+
keyPoints.push(bulletMatch[1] + (bulletMatch[2] ? ': ' + bulletMatch[2] : ''));
543+
} else {
544+
const simpleBullet = line.match(/^\s*[-*]\s+(.+)/);
545+
if (simpleBullet && keyPoints.length < 6) {
546+
keyPoints.push(simpleBullet[1].replace(/\*\*/g, ''));
547+
}
548+
}
549+
if (keyPoints.length >= 6) break;
550+
}
551+
552+
// If no bullet points found, extract first few sentences
553+
if (keyPoints.length === 0) {
554+
const sentences = text.replace(/\*\*/g, '').replace(/#+\s+/g, '').split(/[.!?]+/).filter(s => s.trim().length > 20);
555+
for (let i = 0; i < Math.min(4, sentences.length); i++) {
556+
keyPoints.push(sentences[i].trim());
557+
}
558+
}
559+
560+
// Extract insights from conclusion or findings sections
561+
let insights = '';
562+
const conclusionMatch = text.match(/\*\*Conclusion\*\*\s*\n+([\s\S]*?)(?=\n\*\*|$)/i);
563+
const findingsMatch = text.match(/\*\*Findings\*\*\s*\n+([\s\S]*?)(?=\n\*\*|$)/i);
564+
if (conclusionMatch) {
565+
insights = conclusionMatch[1].replace(/\*\*/g, '').replace(/\n/g, ' ').trim().slice(0, 300);
566+
} else if (findingsMatch) {
567+
insights = findingsMatch[1].replace(/\*\*/g, '').replace(/\n/g, ' ').trim().slice(0, 300);
568+
} else {
569+
// Use a middle paragraph as insights
570+
const paragraphs = text.split(/\n\n+/).filter(p => p.trim().length > 50 && !p.startsWith('#') && !p.startsWith('*'));
571+
if (paragraphs.length > 1) {
572+
insights = paragraphs[Math.floor(paragraphs.length / 2)].replace(/\*\*/g, '').trim().slice(0, 300);
573+
} else if (paragraphs.length === 1) {
574+
insights = paragraphs[0].replace(/\*\*/g, '').trim().slice(0, 300);
575+
}
576+
}
577+
578+
// Extract recommendations
579+
const recommendations = [];
580+
const recMatch = text.match(/\*\*Recommendation[s]?\*\*\s*\n+([\s\S]*?)(?=\n\*\*|$)/i);
581+
if (recMatch) {
582+
const recLines = recMatch[1].split('\n');
583+
for (const line of recLines) {
584+
const bullet = line.match(/^\s*[-*\d.]+\s+\*\*(.+?)\*\*[:\s]*(.*)/);
585+
if (bullet) {
586+
recommendations.push(bullet[1] + (bullet[2] ? ': ' + bullet[2] : ''));
587+
} else {
588+
const simpleBullet = line.match(/^\s*[-*\d.]+\s+(.+)/);
589+
if (simpleBullet) {
590+
recommendations.push(simpleBullet[1].replace(/\*\*/g, ''));
591+
}
592+
}
593+
if (recommendations.length >= 4) break;
594+
}
595+
}
596+
597+
// Fallback recommendations from key points if none found
598+
if (recommendations.length === 0 && keyPoints.length > 2) {
599+
recommendations.push(...keyPoints.slice(-2));
600+
}
601+
602+
// Estimate confidence based on content richness
603+
const wordCount = text.split(/\s+/).length;
604+
const confidence = Math.min(0.95, 0.5 + (wordCount / 2000) * 0.45);
605+
606+
return {
607+
title,
608+
keyPoints: keyPoints.length > 0 ? keyPoints : ['Analysis completed'],
609+
insights: insights || 'Analysis completed successfully. See key points for details.',
610+
recommendations: recommendations.length > 0 ? recommendations : ['Review the full analysis for detailed recommendations'],
611+
confidence
612+
};
599613
}
600614

601615
displayPerspectiveResult(perspectiveId, analysis) {
@@ -655,28 +669,61 @@ class ParallelizationAnalysisDemo {
655669
}
656670

657671
generateAggregatedInsights() {
658-
return [
659-
{
660-
title: 'Convergent Findings',
661-
content: 'All perspectives agree on the fundamental viability and positive potential of the analyzed topic.',
662-
type: 'consensus'
663-
},
664-
{
665-
title: 'Divergent Views',
666-
content: 'Risk assessment varies significantly between perspectives, with critical analysis highlighting more concerns than creative exploration.',
672+
// Build aggregated insights from actual analysis results
673+
const results = Array.from(this.analysisResults.values());
674+
const analyses = results.map(r => r.analysis).filter(Boolean);
675+
676+
if (analyses.length === 0) {
677+
return [{ title: 'No Results', content: 'No perspective analyses were completed.', type: 'info' }];
678+
}
679+
680+
// Collect all key points across perspectives
681+
const allKeyPoints = analyses.flatMap(a => a.keyPoints || []);
682+
const allRecommendations = analyses.flatMap(a => a.recommendations || []);
683+
const perspectiveNames = results.map(r => {
684+
const p = this.perspectives[r.perspectiveId];
685+
return p ? p.name : r.perspectiveId;
686+
});
687+
688+
const insights = [];
689+
690+
// Summarize key findings from all perspectives
691+
insights.push({
692+
title: 'Key Findings Across Perspectives',
693+
content: `${analyses.length} perspectives analyzed (${perspectiveNames.join(', ')}). ` +
694+
`Identified ${allKeyPoints.length} key points: ${allKeyPoints.slice(0, 3).join('; ')}${allKeyPoints.length > 3 ? '...' : ''}.`,
695+
type: 'consensus'
696+
});
697+
698+
// Insights summary
699+
const insightTexts = analyses.map(a => a.insights).filter(Boolean);
700+
if (insightTexts.length > 0) {
701+
insights.push({
702+
title: 'Perspective Insights',
703+
content: insightTexts.map((t, i) => `${perspectiveNames[i]}: ${t.slice(0, 150)}`).join(' | '),
667704
type: 'divergence'
668-
},
669-
{
670-
title: 'Implementation Priority',
671-
content: 'Practical and strategic perspectives suggest a phased approach with clear milestones and risk mitigation.',
672-
type: 'synthesis'
673-
},
674-
{
675-
title: 'Success Factors',
676-
content: 'User-centered design, data-driven decisions, and innovative thinking emerge as key success drivers.',
705+
});
706+
}
707+
708+
// Recommendations synthesis
709+
if (allRecommendations.length > 0) {
710+
insights.push({
711+
title: 'Combined Recommendations',
712+
content: allRecommendations.slice(0, 5).join('. ') + '.',
677713
type: 'synthesis'
678-
}
679-
];
714+
});
715+
}
716+
717+
// Confidence summary
718+
const avgConfidence = analyses.reduce((sum, a) => sum + (a.confidence || 0), 0) / analyses.length;
719+
insights.push({
720+
title: 'Confidence Assessment',
721+
content: `Average confidence across perspectives: ${Math.round(avgConfidence * 100)}%. ` +
722+
analyses.map((a, i) => `${perspectiveNames[i]}: ${Math.round((a.confidence || 0) * 100)}%`).join(', ') + '.',
723+
type: 'synthesis'
724+
});
725+
726+
return insights;
680727
}
681728

682729
displayAggregatedInsights(insights) {

0 commit comments

Comments
 (0)