Add evolver variant generator

This commit is contained in:
Trae AI 2026-05-26 00:00:27 +08:00
parent 5f09f19726
commit 35d0116128
3 changed files with 254 additions and 0 deletions

View file

@ -1,3 +1,4 @@
export * from './types.js';
export * from './metric-evaluator.js';
export * from './resource-manager.js';
export * from './variant-generator.js';

View file

@ -0,0 +1,172 @@
import type {
EvolutionPlan,
MetricExpectation,
MutationType,
RollbackPlan,
VariantPatch,
VariantProvenance,
VariantSpec,
} from './types.js';
export type CurrentParameters = Record<string, unknown>;
const generatedAt = '2026-05-25T00:00:00.000Z';
export function generateVariants(
plan: EvolutionPlan,
currentParameters: CurrentParameters,
): VariantSpec[] {
return plan.allowedMutationTypes.map((mutationType) =>
buildVariant(plan, currentParameters, mutationType),
);
}
function buildVariant(
plan: EvolutionPlan,
currentParameters: CurrentParameters,
mutationType: MutationType,
): VariantSpec {
const expectedGain = defaultExpectedGain();
return {
id: `${plan.id}-${mutationType}-variant`,
planId: plan.id,
mutationType,
description: describeVariant(plan, mutationType),
patch: buildPatch(currentParameters, mutationType),
expectedGain,
riskLevel: riskForMutationType(mutationType),
rollbackPlan: buildRollbackPlan(currentParameters, mutationType),
provenance: buildProvenance(plan, mutationType),
};
}
function describeVariant(plan: EvolutionPlan, mutationType: MutationType): string {
if (mutationType === 'parameter') {
return `Parameter variant for ${plan.targetObject.id}`;
}
if (mutationType === 'algorithm') {
return `Algorithm variant for ${plan.targetObject.id}`;
}
return `Structure review variant for ${plan.targetObject.id}`;
}
function buildPatch(currentParameters: CurrentParameters, mutationType: MutationType): VariantPatch {
if (mutationType === 'parameter') {
const previousValue = currentParameters['retrieval.topK'] ?? 5;
const nextValue = typeof previousValue === 'number' ? previousValue + 1 : 6;
return {
operations: [
{
op: 'setParameter',
path: 'retrieval.topK',
previousValue,
nextValue,
},
],
};
}
if (mutationType === 'algorithm') {
const previousAlgorithm = String(currentParameters['ranking.algorithm'] ?? 'baseline-ranker');
return {
operations: [
{
op: 'selectAlgorithm',
policyId: 'ranking-policy',
previousAlgorithm,
nextAlgorithm: 'candidate-ranker',
},
],
};
}
return {
operations: [
{
op: 'proposeStructureChange',
planPath: 'docs/aegis/plans/structure-change.md',
summary: 'Review structure-level evolution before applying changes',
},
],
};
}
function buildRollbackPlan(
currentParameters: CurrentParameters,
mutationType: MutationType,
): RollbackPlan {
if (mutationType === 'parameter') {
const previousValue = currentParameters['retrieval.topK'] ?? 5;
const candidateValue = typeof previousValue === 'number' ? previousValue + 1 : 6;
return {
strategy: 'restore-previous-parameters',
operations: [
{
op: 'setParameter',
path: 'retrieval.topK',
previousValue: candidateValue,
nextValue: previousValue,
},
],
};
}
if (mutationType === 'algorithm') {
const previousAlgorithm = String(currentParameters['ranking.algorithm'] ?? 'baseline-ranker');
return {
strategy: 'disable-candidate',
operations: [
{
op: 'selectAlgorithm',
policyId: 'ranking-policy',
previousAlgorithm: 'candidate-ranker',
nextAlgorithm: previousAlgorithm,
},
],
};
}
return {
strategy: 'manual-review-required',
operations: [],
};
}
function riskForMutationType(mutationType: MutationType): VariantSpec['riskLevel'] {
if (mutationType === 'parameter') {
return 'low';
}
if (mutationType === 'algorithm') {
return 'medium';
}
return 'high';
}
function defaultExpectedGain(): MetricExpectation[] {
return [
{
metricId: 'task_success_rate',
expectedDelta: 0.05,
direction: 'increase',
},
];
}
function buildProvenance(plan: EvolutionPlan, mutationType: MutationType): VariantProvenance[] {
return [
{
source: 'evolver-variant-generator',
reference: `${plan.id}:${mutationType}`,
capturedAt: generatedAt,
},
];
}

View file

@ -0,0 +1,81 @@
import { describe, expect, it } from 'vitest';
import { generateVariants } from '../../../src/core/evolver/index.js';
import type { EvolutionPlan, ResourceBudget } from '../../../src/core/evolver/index.js';
const resourceBudget: ResourceBudget = {
maxDurationMs: 1000,
maxComputeUnits: 10,
maxApiCostUsd: 1,
maxStorageBytes: 2048,
maxConcurrency: 2,
maxHighRiskVariants: 1,
};
const plan: EvolutionPlan = {
id: 'plan-1',
goalId: 'goal-1',
hypothesis: 'Adjust retrieval and ranking strategy to improve task success rate',
targetObject: {
id: 'retrieval-policy',
kind: 'parameter-set',
description: 'Retrieval policy parameters and selection strategy',
},
allowedMutationTypes: ['parameter', 'algorithm', 'structure'],
evaluationProtocolId: 'protocol-1',
resourceBudget,
};
describe('generateVariants', () => {
it('generates deterministic parameter, algorithm, and structure variants with risk and rollback data', () => {
const variants = generateVariants(plan, {
'retrieval.topK': 5,
'ranking.algorithm': 'baseline-ranker',
});
expect(variants).toHaveLength(3);
expect(variants.map((variant) => variant.id)).toEqual([
'plan-1-parameter-variant',
'plan-1-algorithm-variant',
'plan-1-structure-variant',
]);
expect(variants.map((variant) => variant.mutationType)).toEqual([
'parameter',
'algorithm',
'structure',
]);
expect(variants.map((variant) => variant.riskLevel)).toEqual(['low', 'medium', 'high']);
expect(variants.map((variant) => variant.rollbackPlan.strategy)).toEqual([
'restore-previous-parameters',
'disable-candidate',
'manual-review-required',
]);
expect(variants.every((variant) => variant.provenance.length === 1)).toBe(true);
expect(variants.every((variant) => variant.provenance[0]?.source === 'evolver-variant-generator')).toBe(
true,
);
});
it('only generates mutation types allowed by the plan', () => {
const variants = generateVariants(
{
...plan,
allowedMutationTypes: ['parameter'],
},
{
'retrieval.topK': 5,
'ranking.algorithm': 'baseline-ranker',
},
);
expect(variants).toHaveLength(1);
expect(variants[0]?.mutationType).toBe('parameter');
expect(variants[0]?.patch.operations).toEqual([
{
op: 'setParameter',
path: 'retrieval.topK',
previousValue: 5,
nextValue: 6,
},
]);
});
});