Auto backup before evolver run - 2026年 03月 03日 星期二 23:12:56 CST
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
function stableHash(input) {
|
||||
// Deterministic lightweight hash (not cryptographic).
|
||||
const s = String(input || '');
|
||||
let h = 2166136261;
|
||||
for (let i = 0; i < s.length; i++) {
|
||||
h ^= s.charCodeAt(i);
|
||||
h = Math.imul(h, 16777619);
|
||||
}
|
||||
return (h >>> 0).toString(16).padStart(8, '0');
|
||||
}
|
||||
|
||||
function clip(text, maxChars) {
|
||||
const s = String(text || '');
|
||||
if (!maxChars || s.length <= maxChars) return s;
|
||||
return s.slice(0, Math.max(0, maxChars - 20)) + ' ...[TRUNCATED]';
|
||||
}
|
||||
|
||||
function toLines(text) {
|
||||
return String(text || '')
|
||||
.split('\n')
|
||||
.map(l => l.trimEnd())
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function extractToolCalls(transcript) {
|
||||
const lines = toLines(transcript);
|
||||
const calls = [];
|
||||
for (const line of lines) {
|
||||
const m = line.match(/\[TOOL:\s*([^\]]+)\]/i);
|
||||
if (m && m[1]) calls.push(m[1].trim());
|
||||
}
|
||||
return calls;
|
||||
}
|
||||
|
||||
function countFreq(items) {
|
||||
const map = new Map();
|
||||
for (const it of items) map.set(it, (map.get(it) || 0) + 1);
|
||||
return map;
|
||||
}
|
||||
|
||||
function buildFiveQuestionsShape({ title, signals, evidence }) {
|
||||
// Keep it short and structured; this is a template, not a perfect inference.
|
||||
const input = 'Recent session transcript + memory snippets + user instructions';
|
||||
const output = 'A safe, auditable evolution patch guided by GEP assets';
|
||||
const invariants = 'Protocol order, small reversible patches, validation, append-only events';
|
||||
const params = `Signals: ${Array.isArray(signals) ? signals.join(', ') : ''}`.trim();
|
||||
const failurePoints = 'Missing signals, over-broad changes, skipped validation, missing knowledge solidification';
|
||||
return {
|
||||
title: String(title || '').slice(0, 120),
|
||||
input,
|
||||
output,
|
||||
invariants,
|
||||
params: params || 'Signals: (none)',
|
||||
failure_points: failurePoints,
|
||||
evidence: clip(evidence, 240),
|
||||
};
|
||||
}
|
||||
|
||||
function extractCapabilityCandidates({ recentSessionTranscript, signals }) {
|
||||
const candidates = [];
|
||||
const toolCalls = extractToolCalls(recentSessionTranscript);
|
||||
const freq = countFreq(toolCalls);
|
||||
|
||||
for (const [tool, count] of freq.entries()) {
|
||||
if (count < 2) continue;
|
||||
const title = `Repeated tool usage: ${tool}`;
|
||||
const evidence = `Observed ${count} occurrences of tool call marker for ${tool}.`;
|
||||
const shape = buildFiveQuestionsShape({ title, signals, evidence });
|
||||
candidates.push({
|
||||
type: 'CapabilityCandidate',
|
||||
id: `cand_${stableHash(title)}`,
|
||||
title,
|
||||
source: 'transcript',
|
||||
created_at: new Date().toISOString(),
|
||||
signals: Array.isArray(signals) ? signals : [],
|
||||
shape,
|
||||
});
|
||||
}
|
||||
|
||||
// Signals-as-candidates: capture recurring pain points as reusable capability shapes.
|
||||
const signalList = Array.isArray(signals) ? signals : [];
|
||||
const signalCandidates = [
|
||||
// Defensive signals
|
||||
{ signal: 'log_error', title: 'Repair recurring runtime errors' },
|
||||
{ signal: 'protocol_drift', title: 'Prevent protocol drift and enforce auditable outputs' },
|
||||
{ signal: 'windows_shell_incompatible', title: 'Avoid platform-specific shell assumptions (Windows compatibility)' },
|
||||
{ signal: 'session_logs_missing', title: 'Harden session log detection and fallback behavior' },
|
||||
// Opportunity signals (innovation)
|
||||
{ signal: 'user_feature_request', title: 'Implement user-requested feature' },
|
||||
{ signal: 'user_improvement_suggestion', title: 'Apply user improvement suggestion' },
|
||||
{ signal: 'perf_bottleneck', title: 'Resolve performance bottleneck' },
|
||||
{ signal: 'capability_gap', title: 'Fill capability gap' },
|
||||
{ signal: 'stable_success_plateau', title: 'Explore new strategies during stability plateau' },
|
||||
{ signal: 'external_opportunity', title: 'Evaluate external A2A asset for local adoption' },
|
||||
];
|
||||
|
||||
for (const sc of signalCandidates) {
|
||||
if (!signalList.some(s => s === sc.signal || s.startsWith(sc.signal + ':'))) continue;
|
||||
const evidence = `Signal present: ${sc.signal}`;
|
||||
const shape = buildFiveQuestionsShape({ title: sc.title, signals, evidence });
|
||||
candidates.push({
|
||||
type: 'CapabilityCandidate',
|
||||
id: `cand_${stableHash(sc.signal)}`,
|
||||
title: sc.title,
|
||||
source: 'signals',
|
||||
created_at: new Date().toISOString(),
|
||||
signals: signalList,
|
||||
shape,
|
||||
});
|
||||
}
|
||||
|
||||
// Dedup by id
|
||||
const seen = new Set();
|
||||
return candidates.filter(c => {
|
||||
if (!c || !c.id) return false;
|
||||
if (seen.has(c.id)) return false;
|
||||
seen.add(c.id);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function renderCandidatesPreview(candidates, maxChars = 1400) {
|
||||
const list = Array.isArray(candidates) ? candidates : [];
|
||||
const lines = [];
|
||||
for (const c of list) {
|
||||
const s = c && c.shape ? c.shape : {};
|
||||
lines.push(`- ${c.id}: ${c.title}`);
|
||||
lines.push(` - input: ${s.input || ''}`);
|
||||
lines.push(` - output: ${s.output || ''}`);
|
||||
lines.push(` - invariants: ${s.invariants || ''}`);
|
||||
lines.push(` - params: ${s.params || ''}`);
|
||||
lines.push(` - failure_points: ${s.failure_points || ''}`);
|
||||
if (s.evidence) lines.push(` - evidence: ${s.evidence}`);
|
||||
}
|
||||
return clip(lines.join('\n'), maxChars);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
extractCapabilityCandidates,
|
||||
renderCandidatesPreview,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user