Auto backup before evolver run - 2026年 03月 03日 星期二 23:12:56 CST
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
function clamp01(x) {
|
||||
const n = Number(x);
|
||||
if (!Number.isFinite(n)) return 0;
|
||||
return Math.max(0, Math.min(1, n));
|
||||
}
|
||||
|
||||
function nowTsMs() {
|
||||
return Date.now();
|
||||
}
|
||||
|
||||
function uniqStrings(list) {
|
||||
const out = [];
|
||||
const seen = new Set();
|
||||
for (const x of Array.isArray(list) ? list : []) {
|
||||
const s = String(x || '').trim();
|
||||
if (!s) continue;
|
||||
if (seen.has(s)) continue;
|
||||
seen.add(s);
|
||||
out.push(s);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function hasErrorishSignal(signals) {
|
||||
const list = Array.isArray(signals) ? signals.map(s => String(s || '')) : [];
|
||||
if (list.includes('issue_already_resolved') || list.includes('openclaw_self_healed')) return false;
|
||||
if (list.includes('log_error')) return true;
|
||||
if (list.some(s => s.startsWith('errsig:') || s.startsWith('errsig_norm:'))) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Opportunity signals that indicate a chance to innovate (not just fix).
|
||||
var OPPORTUNITY_SIGNALS = [
|
||||
'user_feature_request',
|
||||
'user_improvement_suggestion',
|
||||
'perf_bottleneck',
|
||||
'capability_gap',
|
||||
'stable_success_plateau',
|
||||
'external_opportunity',
|
||||
'issue_already_resolved',
|
||||
'openclaw_self_healed',
|
||||
'empty_cycle_loop_detected',
|
||||
];
|
||||
|
||||
function hasOpportunitySignal(signals) {
|
||||
var list = Array.isArray(signals) ? signals.map(function (s) { return String(s || ''); }) : [];
|
||||
for (var i = 0; i < OPPORTUNITY_SIGNALS.length; i++) {
|
||||
var name = OPPORTUNITY_SIGNALS[i];
|
||||
if (list.includes(name)) return true;
|
||||
if (list.some(function (s) { return s.startsWith(name + ':'); })) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function mutationCategoryFromContext({ signals, driftEnabled }) {
|
||||
if (hasErrorishSignal(signals)) return 'repair';
|
||||
if (driftEnabled) return 'innovate';
|
||||
// Auto-innovate: opportunity signals present and no errors
|
||||
if (hasOpportunitySignal(signals)) return 'innovate';
|
||||
// Consult strategy preset: if the configured strategy favors innovation,
|
||||
// default to innovate instead of optimize when there is nothing specific to do.
|
||||
try {
|
||||
var strategy = require('./strategy').resolveStrategy();
|
||||
if (strategy && typeof strategy.innovate === 'number' && strategy.innovate >= 0.5) return 'innovate';
|
||||
} catch (_) {}
|
||||
return 'optimize';
|
||||
}
|
||||
|
||||
function expectedEffectFromCategory(category) {
|
||||
const c = String(category || '');
|
||||
if (c === 'repair') return 'reduce runtime errors, increase stability, and lower failure rate';
|
||||
if (c === 'optimize') return 'improve success rate and reduce repeated operational cost';
|
||||
if (c === 'innovate') return 'explore new strategy combinations to escape local optimum';
|
||||
return 'improve robustness and success probability';
|
||||
}
|
||||
|
||||
function targetFromGene(selectedGene) {
|
||||
if (selectedGene && selectedGene.id) return `gene:${String(selectedGene.id)}`;
|
||||
return 'behavior:protocol';
|
||||
}
|
||||
|
||||
function isHighRiskPersonality(p) {
|
||||
// Conservative definition: low rigor or high risk_tolerance is treated as high-risk personality.
|
||||
const rigor = p && Number.isFinite(Number(p.rigor)) ? Number(p.rigor) : null;
|
||||
const riskTol = p && Number.isFinite(Number(p.risk_tolerance)) ? Number(p.risk_tolerance) : null;
|
||||
if (rigor != null && rigor < 0.5) return true;
|
||||
if (riskTol != null && riskTol > 0.6) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function isHighRiskMutationAllowed(personalityState) {
|
||||
const rigor = personalityState && Number.isFinite(Number(personalityState.rigor)) ? Number(personalityState.rigor) : 0;
|
||||
const riskTol =
|
||||
personalityState && Number.isFinite(Number(personalityState.risk_tolerance))
|
||||
? Number(personalityState.risk_tolerance)
|
||||
: 1;
|
||||
return rigor >= 0.6 && riskTol <= 0.5;
|
||||
}
|
||||
|
||||
function buildMutation({
|
||||
signals,
|
||||
selectedGene,
|
||||
driftEnabled,
|
||||
personalityState,
|
||||
allowHighRisk = false,
|
||||
target,
|
||||
expected_effect,
|
||||
} = {}) {
|
||||
const ts = nowTsMs();
|
||||
const category = mutationCategoryFromContext({ signals, driftEnabled: !!driftEnabled });
|
||||
const triggerSignals = uniqStrings(signals);
|
||||
|
||||
const base = {
|
||||
type: 'Mutation',
|
||||
id: `mut_${ts}`,
|
||||
category,
|
||||
trigger_signals: triggerSignals,
|
||||
target: String(target || targetFromGene(selectedGene)),
|
||||
expected_effect: String(expected_effect || expectedEffectFromCategory(category)),
|
||||
risk_level: 'low',
|
||||
};
|
||||
|
||||
// Default risk assignment: innovate is medium; others low.
|
||||
if (category === 'innovate') base.risk_level = 'medium';
|
||||
|
||||
// Optional high-risk escalation (rare, and guarded by strict safety constraints).
|
||||
if (allowHighRisk && category === 'innovate') {
|
||||
base.risk_level = 'high';
|
||||
}
|
||||
|
||||
// Safety constraints (hard):
|
||||
// - forbid innovate + high-risk personality (downgrade innovation to optimize)
|
||||
// - forbid high-risk mutation unless personality satisfies constraints
|
||||
const highRiskPersonality = isHighRiskPersonality(personalityState || null);
|
||||
if (base.category === 'innovate' && highRiskPersonality) {
|
||||
base.category = 'optimize';
|
||||
base.expected_effect = 'safety downgrade: optimize under high-risk personality (avoid innovate+high-risk combo)';
|
||||
base.risk_level = 'low';
|
||||
base.trigger_signals = uniqStrings([...(base.trigger_signals || []), 'safety:avoid_innovate_with_high_risk_personality']);
|
||||
}
|
||||
|
||||
if (base.risk_level === 'high' && !isHighRiskMutationAllowed(personalityState || null)) {
|
||||
// Downgrade rather than emit illegal high-risk mutation.
|
||||
base.risk_level = 'medium';
|
||||
base.trigger_signals = uniqStrings([...(base.trigger_signals || []), 'safety:downgrade_high_risk']);
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
function isValidMutation(obj) {
|
||||
if (!obj || typeof obj !== 'object') return false;
|
||||
if (obj.type !== 'Mutation') return false;
|
||||
if (!obj.id || typeof obj.id !== 'string') return false;
|
||||
if (!obj.category || !['repair', 'optimize', 'innovate'].includes(String(obj.category))) return false;
|
||||
if (!Array.isArray(obj.trigger_signals)) return false;
|
||||
if (!obj.target || typeof obj.target !== 'string') return false;
|
||||
if (!obj.expected_effect || typeof obj.expected_effect !== 'string') return false;
|
||||
if (!obj.risk_level || !['low', 'medium', 'high'].includes(String(obj.risk_level))) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function normalizeMutation(obj) {
|
||||
const m = obj && typeof obj === 'object' ? obj : {};
|
||||
const out = {
|
||||
type: 'Mutation',
|
||||
id: typeof m.id === 'string' ? m.id : `mut_${nowTsMs()}`,
|
||||
category: ['repair', 'optimize', 'innovate'].includes(String(m.category)) ? String(m.category) : 'optimize',
|
||||
trigger_signals: uniqStrings(m.trigger_signals),
|
||||
target: typeof m.target === 'string' ? m.target : 'behavior:protocol',
|
||||
expected_effect: typeof m.expected_effect === 'string' ? m.expected_effect : expectedEffectFromCategory(m.category),
|
||||
risk_level: ['low', 'medium', 'high'].includes(String(m.risk_level)) ? String(m.risk_level) : 'low',
|
||||
};
|
||||
return out;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
clamp01,
|
||||
buildMutation,
|
||||
isValidMutation,
|
||||
normalizeMutation,
|
||||
isHighRiskMutationAllowed,
|
||||
isHighRiskPersonality,
|
||||
hasOpportunitySignal,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user