Loading...
Loading...
Ranks skill matches by fit, performance history, and contextual relevance. Applies multi-factor scoring including success rate, resource usage, and task alignment. Activate on 'rank skills', 'best skill for', 'skill ranking', 'compare skills', 'optimal skill'. NOT for semantic matching (use dag-semantic-matcher) or skill catalog (use dag-skill-registry).
npx skill4agent add erichowens/some_claude_skills dag-capability-rankerinterface RankingFactors {
semanticScore: number; // From semantic matcher (0-1)
successRate: number; // Historical success (0-1)
efficiency: number; // Tokens/time efficiency (0-1)
contextFit: number; // Fit with current context (0-1)
pairingBonus: number; // Bonus for good pairings (0-0.2)
}
interface RankingWeights {
semantic: number;
success: number;
efficiency: number;
context: number;
}
interface RankedSkill {
skillId: string;
rank: number;
finalScore: number;
factors: RankingFactors;
explanation: string;
}
function rankSkills(
candidates: MatchResult[],
registry: SkillRegistry,
context: RankingContext
): RankedSkill[] {
const weights = determineWeights(context);
const scored = candidates.map(match => {
const skill = registry.skills.get(match.skillId);
const factors = calculateFactors(match, skill, context);
const finalScore = computeFinalScore(factors, weights);
return {
skillId: match.skillId,
rank: 0, // Set after sorting
finalScore,
factors,
explanation: generateRankingExplanation(factors, weights),
};
});
// Sort by final score descending
scored.sort((a, b) => b.finalScore - a.finalScore);
// Assign ranks
scored.forEach((item, index) => {
item.rank = index + 1;
});
return scored;
}function calculateFactors(
match: MatchResult,
skill: SkillMetadata,
context: RankingContext
): RankingFactors {
return {
semanticScore: match.score,
successRate: calculateSuccessRate(skill),
efficiency: calculateEfficiency(skill, context),
contextFit: calculateContextFit(skill, context),
pairingBonus: calculatePairingBonus(skill, context),
};
}
function calculateSuccessRate(skill: SkillMetadata): number {
const stats = skill.stats;
// Need minimum executions for confidence
if (stats.totalExecutions < 10) {
return 0.5; // Neutral score for new skills
}
// Apply confidence interval based on sample size
const confidence = Math.min(stats.totalExecutions / 100, 1);
const adjusted = stats.successRate * confidence + 0.7 * (1 - confidence);
return adjusted;
}
function calculateEfficiency(
skill: SkillMetadata,
context: RankingContext
): number {
const stats = skill.stats;
// Token efficiency
const maxTokens = context.tokenBudget ?? 10000;
const tokenScore = 1 - Math.min(stats.averageTokens / maxTokens, 1);
// Time efficiency
const maxTime = context.timeoutMs ?? 60000;
const timeScore = 1 - Math.min(stats.averageDuration / maxTime, 1);
// Combined efficiency (weighted average)
return tokenScore * 0.6 + timeScore * 0.4;
}
function calculateContextFit(
skill: SkillMetadata,
context: RankingContext
): number {
let score = 0.5; // Baseline
// Check if skill category matches task domain
if (context.domain && skill.category.toLowerCase().includes(context.domain)) {
score += 0.2;
}
// Check required tools availability
const availableTools = new Set(context.availableTools ?? []);
const requiredTools = skill.allowedTools;
const toolsAvailable = requiredTools.every(t => availableTools.has(t));
if (toolsAvailable) {
score += 0.2;
}
// Check recent successful use in similar context
if (context.previousSuccesses?.includes(skill.id)) {
score += 0.1;
}
return Math.min(score, 1);
}
function calculatePairingBonus(
skill: SkillMetadata,
context: RankingContext
): number {
let bonus = 0;
const alreadySelected = context.selectedSkills ?? [];
for (const pairing of skill.pairsWith) {
if (alreadySelected.includes(pairing.skillId)) {
switch (pairing.strength) {
case 'required':
bonus += 0.2;
break;
case 'recommended':
bonus += 0.1;
break;
case 'optional':
bonus += 0.05;
break;
}
}
}
return Math.min(bonus, 0.2);
}function determineWeights(context: RankingContext): RankingWeights {
// Default weights
const weights: RankingWeights = {
semantic: 0.4,
success: 0.3,
efficiency: 0.2,
context: 0.1,
};
// Adjust based on context priorities
if (context.priority === 'reliability') {
weights.success = 0.5;
weights.semantic = 0.3;
weights.efficiency = 0.1;
} else if (context.priority === 'speed') {
weights.efficiency = 0.4;
weights.semantic = 0.3;
weights.success = 0.2;
} else if (context.priority === 'accuracy') {
weights.semantic = 0.5;
weights.success = 0.3;
weights.efficiency = 0.1;
}
// Normalize weights to sum to 1
const total = Object.values(weights).reduce((a, b) => a + b, 0);
for (const key of Object.keys(weights) as (keyof RankingWeights)[]) {
weights[key] /= total;
}
return weights;
}function computeFinalScore(
factors: RankingFactors,
weights: RankingWeights
): number {
const baseScore = (
factors.semanticScore * weights.semantic +
factors.successRate * weights.success +
factors.efficiency * weights.efficiency +
factors.contextFit * weights.context
);
// Apply pairing bonus
return Math.min(baseScore + factors.pairingBonus, 1);
}function generateRankingExplanation(
factors: RankingFactors,
weights: RankingWeights
): string {
const contributions = [
{
factor: 'Semantic match',
score: factors.semanticScore,
weight: weights.semantic,
contribution: factors.semanticScore * weights.semantic,
},
{
factor: 'Success history',
score: factors.successRate,
weight: weights.success,
contribution: factors.successRate * weights.success,
},
{
factor: 'Efficiency',
score: factors.efficiency,
weight: weights.efficiency,
contribution: factors.efficiency * weights.efficiency,
},
{
factor: 'Context fit',
score: factors.contextFit,
weight: weights.context,
contribution: factors.contextFit * weights.context,
},
];
// Sort by contribution
contributions.sort((a, b) => b.contribution - a.contribution);
// Build explanation
const topFactors = contributions.slice(0, 2);
const parts = topFactors.map(f =>
`${f.factor}: ${(f.score * 100).toFixed(0)}%`
);
let explanation = `Ranked by: ${parts.join(', ')}`;
if (factors.pairingBonus > 0) {
explanation += ` (+${(factors.pairingBonus * 100).toFixed(0)}% pairing bonus)`;
}
return explanation;
}rankingResults:
query: "Review TypeScript code for bugs"
context:
priority: reliability
domain: code
tokenBudget: 5000
weights:
semantic: 0.30
success: 0.50
efficiency: 0.10
context: 0.10
rankings:
- rank: 1
skillId: code-reviewer
finalScore: 0.89
factors:
semanticScore: 0.92
successRate: 0.94
efficiency: 0.75
contextFit: 0.80
pairingBonus: 0.05
explanation: "Ranked by: Success history: 94%, Semantic match: 92% (+5% pairing bonus)"
- rank: 2
skillId: typescript-expert
finalScore: 0.78
factors:
semanticScore: 0.80
successRate: 0.88
efficiency: 0.70
contextFit: 0.75
pairingBonus: 0
explanation: "Ranked by: Success history: 88%, Semantic match: 80%"
- rank: 3
skillId: security-auditor
finalScore: 0.72
factors:
semanticScore: 0.78
successRate: 0.82
efficiency: 0.60
contextFit: 0.65
pairingBonus: 0
explanation: "Ranked by: Success history: 82%, Semantic match: 78%"
recommendation:
primary: code-reviewer
alternatives: [typescript-expert, security-auditor]
confidence: 0.85dag-semantic-matcherdag-skill-registrydag-graph-builderdag-pattern-learner