musubi-sdd 3.5.1 → 3.6.1
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/README.md +25 -3
- package/bin/musubi-orchestrate.js +309 -0
- package/package.json +1 -1
- package/src/llm-providers/anthropic-provider.js +175 -0
- package/src/llm-providers/base-provider.js +221 -0
- package/src/llm-providers/copilot-provider.js +262 -0
- package/src/llm-providers/index.js +214 -0
- package/src/llm-providers/openai-provider.js +205 -0
- package/src/orchestration/index.js +25 -0
- package/src/orchestration/patterns/swarm.js +111 -4
- package/src/orchestration/replanning/adaptive-goal-modifier.js +1150 -0
- package/src/orchestration/replanning/alternative-generator.js +508 -0
- package/src/orchestration/replanning/config.js +378 -0
- package/src/orchestration/replanning/goal-progress-tracker.js +727 -0
- package/src/orchestration/replanning/index.js +82 -0
- package/src/orchestration/replanning/plan-evaluator.js +455 -0
- package/src/orchestration/replanning/plan-monitor.js +379 -0
- package/src/orchestration/replanning/proactive-path-optimizer.js +972 -0
- package/src/orchestration/replanning/replan-history.js +402 -0
- package/src/orchestration/replanning/replanning-engine.js +706 -0
- package/src/templates/agents/claude-code/CLAUDE.md +45 -0
- package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +20 -0
- package/src/templates/agents/claude-code/skills/orchestrator/patterns.md +89 -0
- package/src/templates/agents/codex/AGENTS.md +13 -0
- package/src/templates/agents/cursor/AGENTS.md +13 -0
- package/src/templates/agents/gemini-cli/GEMINI.md +13 -0
- package/src/templates/agents/github-copilot/AGENTS.md +13 -0
- package/src/templates/agents/qwen-code/QWEN.md +13 -0
- package/src/templates/agents/windsurf/AGENTS.md +13 -0
package/README.md
CHANGED
|
@@ -71,7 +71,23 @@ musubi init --windsurf # Windsurf IDE
|
|
|
71
71
|
|
|
72
72
|
---
|
|
73
73
|
|
|
74
|
-
## 📊 What's New in
|
|
74
|
+
## 📊 What's New in v3.6.1
|
|
75
|
+
|
|
76
|
+
- 🚀 **ProactivePathOptimizer** - Continuous path optimization even during successful execution
|
|
77
|
+
- 🎯 **GoalProgressTracker** - Real-time goal progress monitoring with milestone management
|
|
78
|
+
- 🔄 **AdaptiveGoalModifier** - Dynamic goal adjustment based on execution context
|
|
79
|
+
- 🛠️ **New CLI Commands** - `replan`, `goal`, `optimize`, `path` subcommands for orchestration
|
|
80
|
+
- 📚 **Updated Agent Templates** - All 7 platforms with replanning command documentation
|
|
81
|
+
|
|
82
|
+
### Previous (v3.6.0)
|
|
83
|
+
|
|
84
|
+
- 🧠 **Dynamic Replanning Engine** - AI agents can now dynamically adjust plans when tasks fail
|
|
85
|
+
- 🔌 **LLM Provider Abstraction** - Multi-provider support (Copilot, Anthropic, OpenAI)
|
|
86
|
+
- 📡 **Real-time Plan Monitoring** - Detect failures, timeouts, and quality degradation
|
|
87
|
+
- 🔄 **Alternative Path Generation** - LLM-powered alternative strategies with confidence scoring
|
|
88
|
+
- 📝 **Replan History & Audit** - Full audit trail with JSONL persistence and export
|
|
89
|
+
|
|
90
|
+
### Previous (v3.5.1)
|
|
75
91
|
|
|
76
92
|
- 🔄 **Workflow Engine** - New `musubi-workflow` CLI for stage management and metrics
|
|
77
93
|
- 📊 **Metrics Collection** - Track time per stage, iteration counts, feedback loops
|
|
@@ -80,7 +96,12 @@ musubi init --windsurf # Windsurf IDE
|
|
|
80
96
|
- 🔄 **Retrospective Stage** - Stage 9 for continuous improvement
|
|
81
97
|
- ✅ **Stage Validation Guide** - Checklists for stage transition validation
|
|
82
98
|
|
|
83
|
-
### Previous (
|
|
99
|
+
### Previous (v3.5.1)
|
|
100
|
+
|
|
101
|
+
- 🔧 **CLI Integration** - Added CLI command references to all 8 Claude Code skills
|
|
102
|
+
- 📚 **Platform Documentation** - CLI Commands section added to all 6 non-Claude platforms
|
|
103
|
+
|
|
104
|
+
### v2.1.0
|
|
84
105
|
|
|
85
106
|
- 🔌 **CodeGraphMCPServer Integration** - 14 MCP tools for enhanced code analysis
|
|
86
107
|
- 🧠 **GraphRAG-Powered Search** - Semantic code understanding with Louvain community detection
|
|
@@ -89,7 +110,8 @@ musubi init --windsurf # Windsurf IDE
|
|
|
89
110
|
## Features
|
|
90
111
|
|
|
91
112
|
- 🤖 **Multi-Agent Support** - Works with 7 AI coding agents (Claude Code, GitHub Copilot, Cursor, Gemini CLI, Codex CLI, Qwen Code, Windsurf)
|
|
92
|
-
-
|
|
113
|
+
- 🧠 **Dynamic Replanning** - AI agents dynamically adjust plans on failure with LLM-powered alternatives (v3.6.0+)
|
|
114
|
+
- 🔌 **MCP Server Integration** - CodeGraphMCPServer for advanced code analysis (v2.0.0)
|
|
93
115
|
- 📄 **Flexible Command Formats** - Supports Markdown, TOML, and AGENTS.md formats
|
|
94
116
|
- 🎯 **25 Specialized Agents (All Platforms)** - Orchestrator, Steering, Requirements, Architecture, Development, Quality, Security, Infrastructure
|
|
95
117
|
- Claude Code: Skills API (25 skills)
|
|
@@ -26,6 +26,15 @@ const {
|
|
|
26
26
|
Priority
|
|
27
27
|
} = require('../src/orchestration');
|
|
28
28
|
|
|
29
|
+
const {
|
|
30
|
+
ReplanningEngine,
|
|
31
|
+
GoalProgressTracker,
|
|
32
|
+
Goal,
|
|
33
|
+
AdaptiveGoalModifier,
|
|
34
|
+
ProactivePathOptimizer,
|
|
35
|
+
ModificationReason
|
|
36
|
+
} = require('../src/orchestration/replanning');
|
|
37
|
+
|
|
29
38
|
const program = new Command();
|
|
30
39
|
|
|
31
40
|
program
|
|
@@ -406,6 +415,306 @@ program
|
|
|
406
415
|
}
|
|
407
416
|
});
|
|
408
417
|
|
|
418
|
+
// ============================================================================
|
|
419
|
+
// Replanning Commands
|
|
420
|
+
// ============================================================================
|
|
421
|
+
|
|
422
|
+
// Goal tracking command
|
|
423
|
+
program
|
|
424
|
+
.command('goal')
|
|
425
|
+
.description('Manage goals for goal-driven replanning')
|
|
426
|
+
.argument('<action>', 'Action: list, add, update, remove, status')
|
|
427
|
+
.option('-n, --name <name>', 'Goal name')
|
|
428
|
+
.option('-d, --description <desc>', 'Goal description')
|
|
429
|
+
.option('-p, --priority <priority>', 'Priority (1-10)', '5')
|
|
430
|
+
.option('--deadline <date>', 'Deadline (ISO date)')
|
|
431
|
+
.option('--progress <progress>', 'Progress (0-1)')
|
|
432
|
+
.option('--id <id>', 'Goal ID')
|
|
433
|
+
.option('-f, --format <type>', 'Output format (text|json)', 'text')
|
|
434
|
+
.action(async (action, options) => {
|
|
435
|
+
try {
|
|
436
|
+
const tracker = new GoalProgressTracker();
|
|
437
|
+
|
|
438
|
+
switch (action) {
|
|
439
|
+
case 'add': {
|
|
440
|
+
if (!options.name) {
|
|
441
|
+
console.error(chalk.red('Error: --name is required'));
|
|
442
|
+
process.exit(1);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const goal = tracker.registerGoal({
|
|
446
|
+
name: options.name,
|
|
447
|
+
description: options.description || '',
|
|
448
|
+
priority: parseInt(options.priority, 10),
|
|
449
|
+
deadline: options.deadline ? new Date(options.deadline).getTime() : null
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
console.log(chalk.green(`\n✓ Goal created: ${goal.id}\n`));
|
|
453
|
+
console.log(chalk.cyan(` Name: ${goal.name}`));
|
|
454
|
+
console.log(chalk.dim(` Priority: ${goal.priority}`));
|
|
455
|
+
if (goal.deadline) {
|
|
456
|
+
console.log(chalk.dim(` Deadline: ${new Date(goal.deadline).toISOString()}`));
|
|
457
|
+
}
|
|
458
|
+
console.log('');
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
case 'list': {
|
|
463
|
+
console.log(chalk.bold('\n🎯 Registered Goals\n'));
|
|
464
|
+
|
|
465
|
+
const goals = Array.from(tracker.goals.values());
|
|
466
|
+
|
|
467
|
+
if (options.format === 'json') {
|
|
468
|
+
console.log(JSON.stringify(goals.map(g => g.toJSON()), null, 2));
|
|
469
|
+
} else if (goals.length === 0) {
|
|
470
|
+
console.log(chalk.yellow(' No goals registered'));
|
|
471
|
+
} else {
|
|
472
|
+
for (const goal of goals) {
|
|
473
|
+
const statusIcon = goal.isComplete() ? chalk.green('✓') :
|
|
474
|
+
goal.status === 'in-progress' ? chalk.yellow('◐') :
|
|
475
|
+
chalk.dim('○');
|
|
476
|
+
console.log(` ${statusIcon} ${chalk.cyan(goal.name)} (${goal.id})`);
|
|
477
|
+
console.log(chalk.dim(` Progress: ${(goal.progress * 100).toFixed(0)}% | Priority: ${goal.priority} | Status: ${goal.status}`));
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
console.log('');
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
case 'update': {
|
|
485
|
+
if (!options.id) {
|
|
486
|
+
console.error(chalk.red('Error: --id is required'));
|
|
487
|
+
process.exit(1);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if (options.progress) {
|
|
491
|
+
tracker.updateProgress(options.id, parseFloat(options.progress));
|
|
492
|
+
console.log(chalk.green(`\n✓ Goal ${options.id} updated to ${(parseFloat(options.progress) * 100).toFixed(0)}% progress\n`));
|
|
493
|
+
}
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
case 'status': {
|
|
498
|
+
console.log(chalk.bold('\n📊 Goal Tracking Status\n'));
|
|
499
|
+
console.log(` Goals: ${tracker.goals.size}`);
|
|
500
|
+
console.log(` Tracking: ${tracker.isTracking ? chalk.green('Active') : chalk.dim('Inactive')}`);
|
|
501
|
+
console.log('');
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
default:
|
|
506
|
+
console.error(chalk.red(`Unknown action: ${action}`));
|
|
507
|
+
console.log('Available actions: list, add, update, remove, status');
|
|
508
|
+
process.exit(1);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
} catch (error) {
|
|
512
|
+
console.error(chalk.red(`\n✗ Error: ${error.message}\n`));
|
|
513
|
+
process.exit(1);
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
// Replan command
|
|
518
|
+
program
|
|
519
|
+
.command('replan')
|
|
520
|
+
.description('Trigger replanning analysis')
|
|
521
|
+
.option('-p, --plan <json>', 'Current plan as JSON')
|
|
522
|
+
.option('-f, --plan-file <file>', 'Plan file path')
|
|
523
|
+
.option('--trigger <type>', 'Trigger type (failure|timeout|manual|resource)', 'manual')
|
|
524
|
+
.option('--context <json>', 'Execution context as JSON')
|
|
525
|
+
.option('-o, --output <file>', 'Output file for alternatives')
|
|
526
|
+
.option('--format <type>', 'Output format (text|json)', 'text')
|
|
527
|
+
.action(async (options) => {
|
|
528
|
+
try {
|
|
529
|
+
console.log(chalk.bold('\n🔄 Replanning Analysis\n'));
|
|
530
|
+
|
|
531
|
+
let plan;
|
|
532
|
+
if (options.planFile) {
|
|
533
|
+
plan = await fs.readJson(options.planFile);
|
|
534
|
+
} else if (options.plan) {
|
|
535
|
+
plan = JSON.parse(options.plan);
|
|
536
|
+
} else {
|
|
537
|
+
// Demo plan
|
|
538
|
+
plan = {
|
|
539
|
+
id: 'demo-plan',
|
|
540
|
+
name: 'Demo Plan',
|
|
541
|
+
tasks: [
|
|
542
|
+
{ id: 't1', skill: 'requirements-analyst', name: 'Analyze Requirements' },
|
|
543
|
+
{ id: 't2', skill: 'system-architect', name: 'Design Architecture', dependencies: ['t1'] },
|
|
544
|
+
{ id: 't3', skill: 'code-generator', name: 'Generate Code', dependencies: ['t2'] }
|
|
545
|
+
]
|
|
546
|
+
};
|
|
547
|
+
console.log(chalk.dim(' Using demo plan (provide --plan or --plan-file for custom plan)\n'));
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
const engine = new ReplanningEngine();
|
|
551
|
+
const normalized = engine.normalizePlan(plan);
|
|
552
|
+
|
|
553
|
+
console.log(chalk.bold(' Plan:'));
|
|
554
|
+
console.log(` ID: ${chalk.cyan(normalized.id)}`);
|
|
555
|
+
console.log(` Tasks: ${normalized.tasks.length}`);
|
|
556
|
+
|
|
557
|
+
// Show tasks
|
|
558
|
+
for (const task of normalized.tasks) {
|
|
559
|
+
console.log(chalk.dim(` - ${task.name || task.skill} (${task.id})`));
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
console.log(chalk.bold('\n Analysis:'));
|
|
563
|
+
console.log(` Trigger: ${chalk.yellow(options.trigger)}`);
|
|
564
|
+
console.log(` Status: ${chalk.green('Ready for replanning')}`);
|
|
565
|
+
|
|
566
|
+
if (options.output) {
|
|
567
|
+
await fs.writeJson(options.output, {
|
|
568
|
+
plan: normalized,
|
|
569
|
+
trigger: options.trigger,
|
|
570
|
+
timestamp: new Date().toISOString()
|
|
571
|
+
}, { spaces: 2 });
|
|
572
|
+
console.log(chalk.dim(`\n Output written to: ${options.output}`));
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
console.log('');
|
|
576
|
+
|
|
577
|
+
} catch (error) {
|
|
578
|
+
console.error(chalk.red(`\n✗ Error: ${error.message}\n`));
|
|
579
|
+
process.exit(1);
|
|
580
|
+
}
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
// Goal modification command
|
|
584
|
+
program
|
|
585
|
+
.command('modify-goal')
|
|
586
|
+
.description('Adaptively modify a goal based on constraints')
|
|
587
|
+
.option('--id <id>', 'Goal ID to modify')
|
|
588
|
+
.option('--reason <reason>', 'Modification reason (time|resource|dependency|priority)', 'time')
|
|
589
|
+
.option('--approve', 'Auto-approve modification')
|
|
590
|
+
.option('-f, --format <type>', 'Output format (text|json)', 'text')
|
|
591
|
+
.action(async (options) => {
|
|
592
|
+
try {
|
|
593
|
+
console.log(chalk.bold('\n🔧 Adaptive Goal Modification\n'));
|
|
594
|
+
|
|
595
|
+
const modifier = new AdaptiveGoalModifier({ requireApproval: !options.approve });
|
|
596
|
+
|
|
597
|
+
// Demo goal if no ID provided
|
|
598
|
+
const goal = modifier.registerGoal({
|
|
599
|
+
id: options.id || 'demo-goal',
|
|
600
|
+
name: 'Demo Goal',
|
|
601
|
+
priority: 'high',
|
|
602
|
+
targetDate: new Date(Date.now() + 86400000 * 7).toISOString(),
|
|
603
|
+
deliverables: [
|
|
604
|
+
{ id: 'd1', name: 'Core Feature', priority: 'critical' },
|
|
605
|
+
{ id: 'd2', name: 'Documentation', priority: 'normal' }
|
|
606
|
+
]
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
const reasonMap = {
|
|
610
|
+
time: ModificationReason.TIME_CONSTRAINT,
|
|
611
|
+
resource: ModificationReason.RESOURCE_CONSTRAINT,
|
|
612
|
+
dependency: ModificationReason.DEPENDENCY_FAILURE,
|
|
613
|
+
priority: ModificationReason.PRIORITY_SHIFT
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
const trigger = { reason: reasonMap[options.reason] || ModificationReason.TIME_CONSTRAINT };
|
|
617
|
+
|
|
618
|
+
console.log(chalk.bold(' Goal:'));
|
|
619
|
+
console.log(` ID: ${chalk.cyan(goal.id)}`);
|
|
620
|
+
console.log(` Name: ${goal.name}`);
|
|
621
|
+
console.log(` Priority: ${goal.priority}`);
|
|
622
|
+
|
|
623
|
+
console.log(chalk.bold('\n Trigger:'));
|
|
624
|
+
console.log(` Reason: ${chalk.yellow(trigger.reason)}`);
|
|
625
|
+
|
|
626
|
+
const result = await modifier.triggerModification(goal.id, trigger);
|
|
627
|
+
|
|
628
|
+
console.log(chalk.bold('\n Result:'));
|
|
629
|
+
console.log(` Status: ${result.status === 'applied' ? chalk.green(result.status) : chalk.yellow(result.status)}`);
|
|
630
|
+
|
|
631
|
+
if (result.modification) {
|
|
632
|
+
console.log(` Strategy: ${chalk.cyan(result.modification.strategy.type)}`);
|
|
633
|
+
console.log(` Confidence: ${(result.modification.confidence * 100).toFixed(0)}%`);
|
|
634
|
+
|
|
635
|
+
if (result.modification.impact) {
|
|
636
|
+
console.log(` Impact Score: ${(result.modification.impact.totalScore * 100).toFixed(0)}%`);
|
|
637
|
+
console.log(` Risk Level: ${result.modification.impact.riskLevel}`);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
if (options.format === 'json') {
|
|
642
|
+
console.log('\n' + JSON.stringify(result, null, 2));
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
console.log('');
|
|
646
|
+
|
|
647
|
+
} catch (error) {
|
|
648
|
+
console.error(chalk.red(`\n✗ Error: ${error.message}\n`));
|
|
649
|
+
process.exit(1);
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
// Path optimization command
|
|
654
|
+
program
|
|
655
|
+
.command('optimize-path')
|
|
656
|
+
.description('Analyze and optimize execution path')
|
|
657
|
+
.option('-p, --path <json>', 'Execution path as JSON')
|
|
658
|
+
.option('-f, --path-file <file>', 'Path file')
|
|
659
|
+
.option('--format <type>', 'Output format (text|json)', 'text')
|
|
660
|
+
.action(async (options) => {
|
|
661
|
+
try {
|
|
662
|
+
console.log(chalk.bold('\n⚡ Path Optimization Analysis\n'));
|
|
663
|
+
|
|
664
|
+
const optimizer = new ProactivePathOptimizer(null);
|
|
665
|
+
|
|
666
|
+
let pathData;
|
|
667
|
+
if (options.pathFile) {
|
|
668
|
+
pathData = await fs.readJson(options.pathFile);
|
|
669
|
+
} else if (options.path) {
|
|
670
|
+
pathData = JSON.parse(options.path);
|
|
671
|
+
} else {
|
|
672
|
+
// Demo path
|
|
673
|
+
pathData = {
|
|
674
|
+
pending: [
|
|
675
|
+
{ id: 't1', name: 'Task 1', estimatedDuration: 10000, dependencies: [] },
|
|
676
|
+
{ id: 't2', name: 'Task 2', estimatedDuration: 5000, dependencies: [] },
|
|
677
|
+
{ id: 't3', name: 'Task 3', estimatedDuration: 8000, dependencies: ['t1'] },
|
|
678
|
+
{ id: 't4', name: 'Task 4', estimatedDuration: 3000, dependencies: ['t2', 't3'] }
|
|
679
|
+
]
|
|
680
|
+
};
|
|
681
|
+
console.log(chalk.dim(' Using demo path (provide --path or --path-file for custom)\n'));
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
const metrics = optimizer.calculatePathMetrics(pathData);
|
|
685
|
+
|
|
686
|
+
console.log(chalk.bold(' Path Metrics:'));
|
|
687
|
+
console.log(` Estimated Time: ${chalk.cyan(metrics.estimatedTime + 'ms')}`);
|
|
688
|
+
console.log(` Parallelization Factor: ${(metrics.parallelizationFactor * 100).toFixed(0)}%`);
|
|
689
|
+
console.log(` Risk Score: ${metrics.riskScore.toFixed(2)}`);
|
|
690
|
+
console.log(` Overall Score: ${metrics.getScore().toFixed(2)}`);
|
|
691
|
+
|
|
692
|
+
console.log(chalk.bold('\n Tasks:'));
|
|
693
|
+
for (const task of pathData.pending) {
|
|
694
|
+
const deps = task.dependencies?.length ? ` -> [${task.dependencies.join(', ')}]` : '';
|
|
695
|
+
console.log(chalk.dim(` - ${task.name} (${task.id})${deps}`));
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
if (options.format === 'json') {
|
|
699
|
+
console.log('\n' + JSON.stringify({
|
|
700
|
+
path: pathData,
|
|
701
|
+
metrics: {
|
|
702
|
+
estimatedTime: metrics.estimatedTime,
|
|
703
|
+
parallelizationFactor: metrics.parallelizationFactor,
|
|
704
|
+
riskScore: metrics.riskScore,
|
|
705
|
+
score: metrics.getScore()
|
|
706
|
+
}
|
|
707
|
+
}, null, 2));
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
console.log('');
|
|
711
|
+
|
|
712
|
+
} catch (error) {
|
|
713
|
+
console.error(chalk.red(`\n✗ Error: ${error.message}\n`));
|
|
714
|
+
process.exit(1);
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
|
|
409
718
|
// Status command
|
|
410
719
|
program
|
|
411
720
|
.command('status')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "musubi-sdd",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.1",
|
|
4
4
|
"description": "Ultimate Specification Driven Development Tool with 27 Agents for 7 AI Coding Platforms + MCP Integration (Claude Code, GitHub Copilot, Cursor, Gemini CLI, Windsurf, Codex, Qwen Code)",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Anthropic Claude API Provider for MUSUBI Replanning Engine
|
|
3
|
+
* @module llm-providers/anthropic-provider
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const { LLMProvider } = require('./base-provider');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Anthropic Claude API Provider
|
|
13
|
+
* Used when running outside VS Code or when Claude is preferred
|
|
14
|
+
*/
|
|
15
|
+
class AnthropicLMProvider extends LLMProvider {
|
|
16
|
+
/**
|
|
17
|
+
* Create an Anthropic provider
|
|
18
|
+
* @param {Object} config - Provider configuration
|
|
19
|
+
* @param {string} [config.apiKey] - Anthropic API key
|
|
20
|
+
* @param {string} [config.model='claude-sonnet-4-20250514'] - Model to use
|
|
21
|
+
*/
|
|
22
|
+
constructor(config = {}) {
|
|
23
|
+
super(config);
|
|
24
|
+
this.name = 'anthropic';
|
|
25
|
+
this.apiKey = config.apiKey || process.env.ANTHROPIC_API_KEY;
|
|
26
|
+
this.config.model = config.model || 'claude-sonnet-4-20250514';
|
|
27
|
+
this.endpoint = config.endpoint || 'https://api.anthropic.com/v1/messages';
|
|
28
|
+
this.rateLimiter = this.createRateLimiter(60); // 60 RPM
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Initialize the Anthropic provider
|
|
33
|
+
* @returns {Promise<void>}
|
|
34
|
+
*/
|
|
35
|
+
async initialize() {
|
|
36
|
+
if (!this.apiKey) {
|
|
37
|
+
throw new Error('Anthropic API key not found. Set ANTHROPIC_API_KEY environment variable.');
|
|
38
|
+
}
|
|
39
|
+
this.isInitialized = true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Complete a prompt using Anthropic Claude API
|
|
44
|
+
* @param {string} prompt - The prompt to complete
|
|
45
|
+
* @param {Object} [options={}] - Completion options
|
|
46
|
+
* @returns {Promise<LLMCompletionResult>} Completion result
|
|
47
|
+
*/
|
|
48
|
+
async complete(prompt, options = {}) {
|
|
49
|
+
if (!this.isInitialized) {
|
|
50
|
+
await this.initialize();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const systemPrompt = options.systemPrompt || this.getDefaultSystemPrompt();
|
|
54
|
+
|
|
55
|
+
return this.rateLimiter(async () => {
|
|
56
|
+
return this.retryWithBackoff(async () => {
|
|
57
|
+
const response = await fetch(this.endpoint, {
|
|
58
|
+
method: 'POST',
|
|
59
|
+
headers: {
|
|
60
|
+
'x-api-key': this.apiKey,
|
|
61
|
+
'anthropic-version': '2023-06-01',
|
|
62
|
+
'content-type': 'application/json'
|
|
63
|
+
},
|
|
64
|
+
body: JSON.stringify({
|
|
65
|
+
model: this.config.model,
|
|
66
|
+
max_tokens: options.maxTokens || this.config.maxTokens,
|
|
67
|
+
system: systemPrompt,
|
|
68
|
+
messages: [
|
|
69
|
+
{ role: 'user', content: prompt }
|
|
70
|
+
]
|
|
71
|
+
}),
|
|
72
|
+
signal: AbortSignal.timeout(this.config.timeout)
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
const error = await response.text();
|
|
77
|
+
throw new Error(`Anthropic API error: ${response.status} - ${error}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const data = await response.json();
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
content: data.content[0].text,
|
|
84
|
+
model: data.model,
|
|
85
|
+
usage: {
|
|
86
|
+
promptTokens: data.usage?.input_tokens || 0,
|
|
87
|
+
completionTokens: data.usage?.output_tokens || 0,
|
|
88
|
+
totalTokens: (data.usage?.input_tokens || 0) + (data.usage?.output_tokens || 0)
|
|
89
|
+
},
|
|
90
|
+
finishReason: data.stop_reason
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Generate embeddings (not natively supported by Anthropic)
|
|
98
|
+
* @param {string} text - Text to embed
|
|
99
|
+
* @returns {Promise<number[]>}
|
|
100
|
+
*/
|
|
101
|
+
async embed(text) {
|
|
102
|
+
throw new Error('Embedding not supported by Anthropic Claude API. Use OpenAI or a dedicated embedding service.');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Check if the provider is available
|
|
107
|
+
* @returns {Promise<boolean>}
|
|
108
|
+
*/
|
|
109
|
+
async isAvailable() {
|
|
110
|
+
if (!this.apiKey) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
// Simple validation - check if API key format is valid
|
|
116
|
+
// Anthropic API keys start with 'sk-ant-'
|
|
117
|
+
return this.apiKey.startsWith('sk-ant-') || this.apiKey.length > 20;
|
|
118
|
+
} catch (e) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get provider information
|
|
125
|
+
* @returns {ProviderInfo}
|
|
126
|
+
*/
|
|
127
|
+
getInfo() {
|
|
128
|
+
return {
|
|
129
|
+
name: this.name,
|
|
130
|
+
model: this.config.model,
|
|
131
|
+
isInitialized: this.isInitialized,
|
|
132
|
+
capabilities: {
|
|
133
|
+
completion: true,
|
|
134
|
+
embedding: false,
|
|
135
|
+
streaming: true,
|
|
136
|
+
functionCalling: true
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Get default system prompt for replanning
|
|
143
|
+
* @returns {string}
|
|
144
|
+
* @private
|
|
145
|
+
*/
|
|
146
|
+
getDefaultSystemPrompt() {
|
|
147
|
+
return `You are an AI assistant helping with task replanning in a software development workflow.
|
|
148
|
+
Your role is to analyze failed tasks, understand the goal, and generate alternative approaches.
|
|
149
|
+
|
|
150
|
+
Guidelines:
|
|
151
|
+
1. Be concise and specific in your recommendations
|
|
152
|
+
2. Prioritize practical, actionable alternatives
|
|
153
|
+
3. Consider resource constraints and dependencies
|
|
154
|
+
4. Provide confidence scores for each alternative (0.0 to 1.0)
|
|
155
|
+
5. Explain the reasoning behind each suggestion
|
|
156
|
+
|
|
157
|
+
When generating alternatives, output valid JSON with this structure:
|
|
158
|
+
{
|
|
159
|
+
"analysis": "Brief analysis of the failure",
|
|
160
|
+
"goal": "Extracted goal from the task",
|
|
161
|
+
"alternatives": [
|
|
162
|
+
{
|
|
163
|
+
"id": "alt-1",
|
|
164
|
+
"description": "Alternative approach",
|
|
165
|
+
"task": { "name": "task-name", "skill": "skill-name", "parameters": {} },
|
|
166
|
+
"confidence": 0.8,
|
|
167
|
+
"reasoning": "Why this might work",
|
|
168
|
+
"risks": ["potential risk"]
|
|
169
|
+
}
|
|
170
|
+
]
|
|
171
|
+
}`;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
module.exports = { AnthropicLMProvider };
|