@evomap/evolver 1.89.14 → 1.89.17
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/index.js +219 -29
- package/package.json +1 -1
- package/src/adapters/claudeCode.js +2 -2
- package/src/adapters/codex.js +2 -2
- package/src/adapters/hookAdapter.js +14 -2
- package/src/adapters/scripts/evolver-session-start.js +182 -2
- package/src/config.js +11 -3
- package/src/evolve/guards.js +1 -1
- package/src/evolve/pipeline/collect.js +1 -1
- package/src/evolve/pipeline/dispatch.js +1 -1
- package/src/evolve/pipeline/enrich.js +1 -1
- package/src/evolve/pipeline/hub.js +1 -1
- package/src/evolve/pipeline/select.js +1 -1
- package/src/evolve/pipeline/signals.js +1 -1
- package/src/evolve/utils.js +1 -1
- package/src/evolve.js +1 -1
- package/src/forceUpdate.js +499 -119
- package/src/gep/a2aProtocol.js +1 -1
- package/src/gep/antiAbuseTelemetry.js +1 -1
- package/src/gep/autoDistillConv.js +1 -1
- package/src/gep/autoDistillLlm.js +1 -1
- package/src/gep/candidateEval.js +1 -1
- package/src/gep/candidates.js +1 -1
- package/src/gep/cliContracts.js +1154 -0
- package/src/gep/contentHash.js +1 -1
- package/src/gep/conversationDistiller.js +1 -1
- package/src/gep/conversationSniffer.js +1 -1
- package/src/gep/crypto.js +1 -1
- package/src/gep/curriculum.js +1 -1
- package/src/gep/deviceId.js +1 -1
- package/src/gep/envFingerprint.js +1 -1
- package/src/gep/epigenetics.js +1 -1
- package/src/gep/execBridge.js +1 -1
- package/src/gep/explore.js +1 -1
- package/src/gep/hash.js +1 -1
- package/src/gep/hostErrorClassifier.js +34 -0
- package/src/gep/hubFetch.js +1 -1
- package/src/gep/hubReview.js +1 -1
- package/src/gep/hubSearch.js +1 -1
- package/src/gep/hubVerify.js +1 -1
- package/src/gep/issueReporter.js +87 -0
- package/src/gep/learningSignals.js +1 -1
- package/src/gep/memoryGraph.js +1 -1
- package/src/gep/memoryGraphAdapter.js +1 -1
- package/src/gep/mutation.js +1 -1
- package/src/gep/narrativeMemory.js +1 -1
- package/src/gep/openPRRegistry.js +1 -1
- package/src/gep/paths.js +20 -0
- package/src/gep/personality.js +1 -1
- package/src/gep/policyCheck.js +1 -1
- package/src/gep/prompt.js +1 -1
- package/src/gep/recallInject.js +1 -1
- package/src/gep/recallVerifier.js +1 -1
- package/src/gep/reflection.js +1 -1
- package/src/gep/sanitize.js +20 -4
- package/src/gep/savingsCore.js +1 -1
- package/src/gep/selector.js +1 -1
- package/src/gep/signals.js +70 -24
- package/src/gep/skillDistiller.js +1 -1
- package/src/gep/solidify.js +1 -1
- package/src/gep/strategy.js +1 -1
- package/src/gep/tokenSavings.js +1 -1
- package/src/gep/workspaceKeychain.js +1 -1
- package/src/ops/lifecycle.js +501 -31
- package/src/proxy/extensions/traceControl.js +1 -1
- package/src/proxy/index.js +4 -4
- package/src/proxy/inject.js +1 -1
- package/src/proxy/lifecycle/manager.js +233 -33
- package/src/proxy/sync/inbound.js +5 -4
- package/src/proxy/sync/outbound.js +3 -2
- package/src/proxy/trace/extractor.js +1 -1
- package/src/proxy/trace/usage.js +1 -1
package/src/gep/signals.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
var { isHostClientError } = require('./hostErrorClassifier');
|
|
2
|
+
|
|
1
3
|
// Opportunity signal names (shared with mutation.js and personality.js).
|
|
2
4
|
var OPPORTUNITY_SIGNALS = [
|
|
3
5
|
'user_feature_request',
|
|
@@ -32,6 +34,22 @@ function hasOpportunitySignal(signals) {
|
|
|
32
34
|
return false;
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
// A cycle that produced no file/line changes is a no-op ("empty cycle"), not a
|
|
38
|
+
// genuine failure -- even when its outcome is recorded as `failed`. The most
|
|
39
|
+
// common way a `failed` event ends up with zero blast radius is a claimed-
|
|
40
|
+
// success cycle rejected by the anti-forgery guard (`zero_blast_radius_with_
|
|
41
|
+
// success`): the sub-agent declared success but touched nothing -- e.g. an
|
|
42
|
+
// `innovate` gene that only produces metadata/strategy and never edits code.
|
|
43
|
+
// Empty cycles are tracked separately (consecutiveEmptyCycles) and drive
|
|
44
|
+
// graceful steady-state degradation, NOT the failure-loop ban. Single source of
|
|
45
|
+
// truth so the empty/failure split stays consistent across every counter below.
|
|
46
|
+
function _isEmptyCycle(evt) {
|
|
47
|
+
if (!evt) return false;
|
|
48
|
+
if (evt.meta && evt.meta.empty_cycle) return true;
|
|
49
|
+
var br = evt.blast_radius;
|
|
50
|
+
return !!(br && br.files === 0 && br.lines === 0);
|
|
51
|
+
}
|
|
52
|
+
|
|
35
53
|
// Build a de-duplication set from recent evolution events.
|
|
36
54
|
// Returns an object: { suppressedSignals: Set<string>, recentIntents: string[], consecutiveRepairCount: number }
|
|
37
55
|
function analyzeRecentHistory(recentEvents) {
|
|
@@ -85,13 +103,11 @@ function analyzeRecentHistory(recentEvents) {
|
|
|
85
103
|
|
|
86
104
|
var recentIntents = recent.map(function(e) { return e.intent || 'unknown'; });
|
|
87
105
|
|
|
88
|
-
// Count empty cycles (
|
|
106
|
+
// Count empty cycles (no file/line changes) in last 8 events.
|
|
89
107
|
// High ratio indicates the evolver is spinning without producing real changes.
|
|
90
108
|
var emptyCycleCount = 0;
|
|
91
109
|
for (var ec = 0; ec < tail.length; ec++) {
|
|
92
|
-
|
|
93
|
-
var em = tail[ec].meta && tail[ec].meta.empty_cycle;
|
|
94
|
-
if (em || (br && br.files === 0 && br.lines === 0)) {
|
|
110
|
+
if (_isEmptyCycle(tail[ec])) {
|
|
95
111
|
emptyCycleCount++;
|
|
96
112
|
}
|
|
97
113
|
}
|
|
@@ -101,19 +117,25 @@ function analyzeRecentHistory(recentEvents) {
|
|
|
101
117
|
// zero-change cycles. Used to trigger graceful degradation to steady-state mode.
|
|
102
118
|
var consecutiveEmptyCycles = 0;
|
|
103
119
|
for (var se = recent.length - 1; se >= 0; se--) {
|
|
104
|
-
|
|
105
|
-
var seEm = recent[se].meta && recent[se].meta.empty_cycle;
|
|
106
|
-
if (seEm || (seBr && seBr.files === 0 && seBr.lines === 0)) {
|
|
120
|
+
if (_isEmptyCycle(recent[se])) {
|
|
107
121
|
consecutiveEmptyCycles++;
|
|
108
122
|
} else {
|
|
109
123
|
break;
|
|
110
124
|
}
|
|
111
125
|
}
|
|
112
126
|
|
|
113
|
-
// Count consecutive failures at the tail of recent events.
|
|
127
|
+
// Count consecutive *productive* failures at the tail of recent events.
|
|
114
128
|
// This tells the evolver "you have been failing N times in a row -- slow down."
|
|
129
|
+
//
|
|
130
|
+
// A no-op (zero-blast) cycle breaks the streak instead of extending it: it is
|
|
131
|
+
// already counted as an empty cycle above, which drives graceful steady-state
|
|
132
|
+
// degradation. Without this guard a gene that keeps producing empty cycles --
|
|
133
|
+
// or a sub-agent whose claimed-success cycles are anti-forgery-rejected to
|
|
134
|
+
// `failed` with zero blast radius -- would double-trigger failure_loop_detected
|
|
135
|
+
// + ban_gene and file a spurious recurring-failure GitHub issue (see #577).
|
|
115
136
|
var consecutiveFailureCount = 0;
|
|
116
137
|
for (var cf = recent.length - 1; cf >= 0; cf--) {
|
|
138
|
+
if (_isEmptyCycle(recent[cf])) break;
|
|
117
139
|
var outcome = recent[cf].outcome;
|
|
118
140
|
if (outcome && outcome.status === 'failed') {
|
|
119
141
|
consecutiveFailureCount++;
|
|
@@ -122,9 +144,12 @@ function analyzeRecentHistory(recentEvents) {
|
|
|
122
144
|
}
|
|
123
145
|
}
|
|
124
146
|
|
|
125
|
-
// Count total failures in last 8 events (failure ratio).
|
|
147
|
+
// Count total *productive* failures in last 8 events (failure ratio).
|
|
148
|
+
// Empty (zero-blast) cycles are excluded for the same reason as the
|
|
149
|
+
// consecutive-failure streak above -- a no-op is saturation, not a failure.
|
|
126
150
|
var recentFailureCount = 0;
|
|
127
151
|
for (var rf = 0; rf < tail.length; rf++) {
|
|
152
|
+
if (_isEmptyCycle(tail[rf])) continue;
|
|
128
153
|
var rfOut = tail[rf].outcome;
|
|
129
154
|
if (rfOut && rfOut.status === 'failed') recentFailureCount++;
|
|
130
155
|
}
|
|
@@ -595,6 +620,12 @@ function extractSignals({ recentSessionTranscript, todayLog, memorySnippet, user
|
|
|
595
620
|
|
|
596
621
|
var history = analyzeRecentHistory(recentEvents || []);
|
|
597
622
|
|
|
623
|
+
// Is the recent failure corpus dominated by an unrecoverable host/LLM client
|
|
624
|
+
// error (4xx: malformed request / auth / quota)? Such failures are the host
|
|
625
|
+
// Agent's provider config, not the Gene -- they must not feed the
|
|
626
|
+
// failure-loop streak / ban_gene path below (#571, follow-up to #534).
|
|
627
|
+
var hostClientError = isHostClientError(corpus);
|
|
628
|
+
|
|
598
629
|
var errorHit = /\[error\]|error:|exception:|iserror":true|"status":\s*"error"|"status":\s*"failed"|错误\s*[::]|异常\s*[::]|报错\s*[::]|失败\s*[::]/.test(lower);
|
|
599
630
|
|
|
600
631
|
// Layer 1: Regex (deterministic, 0ms)
|
|
@@ -673,28 +704,42 @@ function extractSignals({ recentSessionTranscript, todayLog, memorySnippet, user
|
|
|
673
704
|
|
|
674
705
|
// Failure streak awareness
|
|
675
706
|
if (history.consecutiveFailureCount >= 3) {
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
707
|
+
if (hostClientError) {
|
|
708
|
+
// Non-Gene-attributable: an unrecoverable host/LLM 4xx is driving the
|
|
709
|
+
// streak. Surface an actionable signal pointing at the host LLM config
|
|
710
|
+
// and skip the streak/ban path so we never ban an innocent Gene or trip
|
|
711
|
+
// failure_loop_detected (#571).
|
|
712
|
+
if (!signals.includes('host_llm_client_error')) signals.push('host_llm_client_error');
|
|
713
|
+
} else {
|
|
714
|
+
signals.push('consecutive_failure_streak_' + history.consecutiveFailureCount);
|
|
715
|
+
if (history.consecutiveFailureCount >= 5) {
|
|
716
|
+
signals.push('failure_loop_detected');
|
|
717
|
+
var topGene = null;
|
|
718
|
+
var topGeneCount = 0;
|
|
719
|
+
var gfEntries = Object.entries(history.geneFreq);
|
|
720
|
+
for (var gfi = 0; gfi < gfEntries.length; gfi++) {
|
|
721
|
+
if (gfEntries[gfi][1] > topGeneCount) {
|
|
722
|
+
topGeneCount = gfEntries[gfi][1];
|
|
723
|
+
topGene = gfEntries[gfi][0];
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
if (topGene) {
|
|
727
|
+
signals.push('ban_gene:' + topGene);
|
|
686
728
|
}
|
|
687
|
-
}
|
|
688
|
-
if (topGene) {
|
|
689
|
-
signals.push('ban_gene:' + topGene);
|
|
690
729
|
}
|
|
691
730
|
}
|
|
692
731
|
}
|
|
693
732
|
|
|
694
733
|
// High failure ratio in recent history (>= 75% failed in last 8 cycles)
|
|
695
734
|
if (history.recentFailureRatio >= 0.75) {
|
|
696
|
-
|
|
697
|
-
|
|
735
|
+
if (hostClientError) {
|
|
736
|
+
// Same rationale as the streak block: a host/LLM 4xx is not the Gene's
|
|
737
|
+
// fault, so do not force innovation away from it (#571).
|
|
738
|
+
if (!signals.includes('host_llm_client_error')) signals.push('host_llm_client_error');
|
|
739
|
+
} else {
|
|
740
|
+
signals.push('high_failure_ratio');
|
|
741
|
+
signals.push('force_innovation_after_repair_loop');
|
|
742
|
+
}
|
|
698
743
|
}
|
|
699
744
|
|
|
700
745
|
// Plateau detection: recent scores trending down or stagnant.
|
|
@@ -727,4 +772,5 @@ module.exports = {
|
|
|
727
772
|
OPPORTUNITY_SIGNALS, SIGNAL_PROFILES,
|
|
728
773
|
_extractRegex, _extractKeywordScore, _extractLLM, _mergeSignals,
|
|
729
774
|
_curlHubIpFamilyArgs, _curlHubIpFamilyAttempts, _curlAuthConfig,
|
|
775
|
+
_isEmptyCycle,
|
|
730
776
|
};
|