darwin-agents 0.9.0 → 0.10.0

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +48 -0
  3. package/dist/src/cli/evolution-flags.d.ts +2 -0
  4. package/dist/src/cli/evolution-flags.d.ts.map +1 -1
  5. package/dist/src/cli/evolution-flags.js +36 -1
  6. package/dist/src/cli/evolution-flags.js.map +1 -1
  7. package/dist/src/cli/evolve.d.ts +2 -0
  8. package/dist/src/cli/evolve.d.ts.map +1 -1
  9. package/dist/src/cli/evolve.js +10 -0
  10. package/dist/src/cli/evolve.js.map +1 -1
  11. package/dist/src/cli/index.js +2 -0
  12. package/dist/src/cli/index.js.map +1 -1
  13. package/dist/src/evolution/demos.d.ts +128 -0
  14. package/dist/src/evolution/demos.d.ts.map +1 -0
  15. package/dist/src/evolution/demos.js +196 -0
  16. package/dist/src/evolution/demos.js.map +1 -0
  17. package/dist/src/evolution/enabled-state.d.ts +5 -5
  18. package/dist/src/evolution/enabled-state.d.ts.map +1 -1
  19. package/dist/src/evolution/enabled-state.js +10 -5
  20. package/dist/src/evolution/enabled-state.js.map +1 -1
  21. package/dist/src/evolution/loop.d.ts +36 -0
  22. package/dist/src/evolution/loop.d.ts.map +1 -1
  23. package/dist/src/evolution/loop.js +118 -19
  24. package/dist/src/evolution/loop.js.map +1 -1
  25. package/dist/src/evolution/selection.d.ts +73 -0
  26. package/dist/src/evolution/selection.d.ts.map +1 -0
  27. package/dist/src/evolution/selection.js +121 -0
  28. package/dist/src/evolution/selection.js.map +1 -0
  29. package/dist/src/index.d.ts +2 -0
  30. package/dist/src/index.d.ts.map +1 -1
  31. package/dist/src/index.js +10 -0
  32. package/dist/src/index.js.map +1 -1
  33. package/dist/src/types.d.ts +67 -0
  34. package/dist/src/types.d.ts.map +1 -1
  35. package/dist/src/types.js.map +1 -1
  36. package/package.json +4 -1
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Demo injection (v0.10.0) — SIMBA-style "append a demo" challenger source.
3
+ *
4
+ * DSPy's SIMBA optimizer (Stochastic Introspective Mini-Batch Ascent) improves
5
+ * programs through two complementary strategies: appending self-reflective
6
+ * RULES (Darwin's reflector already covers that ground) and appending
7
+ * successful past examples as DEMONSTRATIONS. This module is Darwin's
8
+ * adaptation of the second strategy to the online evolution loop:
9
+ *
10
+ * 1. Harvest the agent's own highest-scoring past runs from memory
11
+ * (score ≥ threshold, successful, non-trivial output).
12
+ * 2. Prefer diversity: at most one demo per task type, best-scoring first.
13
+ * 3. Render them as a clearly-delimited "Demonstrations" section and
14
+ * append it to (or refresh it inside) the current prompt.
15
+ *
16
+ * The demo-augmented prompt is a CHALLENGER like any other — it goes through
17
+ * the same alignment guard, the same A/B test, and the same safety gate as a
18
+ * reflective or merged mutation. If demos don't actually help this agent, the
19
+ * incumbent wins and nothing changes.
20
+ *
21
+ * Design notes:
22
+ * - Zero LLM cost. Selection and rendering are pure string/array work on
23
+ * data Darwin already persists (task, output, score, taskType). This makes
24
+ * demos the cheapest challenger source in the loop.
25
+ * - Idempotent via markers. The section is wrapped in
26
+ * `<!-- darwin:demos:start/end -->` comments so a later demo cycle
27
+ * REPLACES the previous section instead of stacking a second one, and
28
+ * {@link stripDemoSection} can remove it cleanly.
29
+ * - Demo text comes from the agent's OWN prior outputs (already produced
30
+ * under this prompt lineage), not from an external input channel. Excerpts
31
+ * are length-capped and fenced, but callers embedding third-party data in
32
+ * tasks should be aware demos quote past tasks verbatim.
33
+ * - Determinism. Given the same experiment list and options, selection and
34
+ * rendering are fully deterministic (stable sort, no randomness) — the
35
+ * loop's no-op check ("would this produce the same prompt?") stays cheap.
36
+ */
37
+ // ─── Defaults & markers ─────────────────────────────────────────────────────
38
+ export const DEFAULT_MAX_DEMOS = 2;
39
+ export const DEFAULT_DEMO_SCORE_THRESHOLD = 8;
40
+ export const DEFAULT_DEMO_MIN_OUTPUT_CHARS = 200;
41
+ export const DEFAULT_DEMO_TASK_CHARS = 240;
42
+ export const DEFAULT_DEMO_OUTPUT_CHARS = 900;
43
+ /** Start marker — everything between the markers is Darwin-managed. */
44
+ export const DEMO_SECTION_START = "<!-- darwin:demos:start -->";
45
+ /** End marker. */
46
+ export const DEMO_SECTION_END = "<!-- darwin:demos:end -->";
47
+ const DEMO_SECTION_INTRO = "## Demonstrations\n" +
48
+ "The following are excerpts from this agent's own highest-rated past " +
49
+ "responses. Match their quality, depth and structure — do NOT copy their " +
50
+ "content or treat their subject matter as part of the current task.";
51
+ // ─── Selection ──────────────────────────────────────────────────────────────
52
+ /** Clamp helper: finite number ≥ min, else fallback. */
53
+ function clampOption(value, min, fallback) {
54
+ return typeof value === "number" && Number.isFinite(value) && value >= min
55
+ ? Math.floor(value)
56
+ : fallback;
57
+ }
58
+ /**
59
+ * Harvest demo candidates from an agent's experiment history.
60
+ *
61
+ * Filter: successful runs with a critic score ≥ `scoreThreshold` and an
62
+ * output of at least `minOutputChars`. Diversity: at most ONE demo per task
63
+ * type (the best-scoring run of that type, recency as tie-break) so two demos
64
+ * never showcase the same narrow strength. Order: score descending, then
65
+ * most-recent first — fully deterministic.
66
+ */
67
+ export function selectDemoCandidates(experiments, options = {}) {
68
+ const maxDemos = clampOption(options.maxDemos, 1, DEFAULT_MAX_DEMOS);
69
+ const threshold = typeof options.scoreThreshold === "number" && Number.isFinite(options.scoreThreshold)
70
+ ? options.scoreThreshold
71
+ : DEFAULT_DEMO_SCORE_THRESHOLD;
72
+ const minChars = clampOption(options.minOutputChars, 0, DEFAULT_DEMO_MIN_OUTPUT_CHARS);
73
+ const qualified = experiments.filter((exp) => {
74
+ if (!exp.success)
75
+ return false;
76
+ const score = exp.feedback?.score;
77
+ if (typeof score !== "number" || !Number.isFinite(score) || score < threshold)
78
+ return false;
79
+ const output = exp.output;
80
+ if (typeof output !== "string" || output.trim().length < minChars)
81
+ return false;
82
+ return typeof exp.task === "string" && exp.task.trim().length > 0;
83
+ });
84
+ // Best run per task type (score desc, then completedAt desc as tie-break).
85
+ const bestPerType = new Map();
86
+ for (const exp of qualified) {
87
+ const key = exp.taskType || "general";
88
+ const incumbent = bestPerType.get(key);
89
+ if (incumbent === undefined) {
90
+ bestPerType.set(key, exp);
91
+ continue;
92
+ }
93
+ const expScore = exp.feedback.score;
94
+ const incScore = incumbent.feedback.score;
95
+ if (expScore > incScore ||
96
+ (expScore === incScore && exp.completedAt > incumbent.completedAt)) {
97
+ bestPerType.set(key, exp);
98
+ }
99
+ }
100
+ const picked = [...bestPerType.values()].sort((a, b) => {
101
+ const scoreDelta = b.feedback.score - a.feedback.score;
102
+ if (scoreDelta !== 0)
103
+ return scoreDelta;
104
+ // Recency tie-break; ISO timestamps sort lexicographically.
105
+ if (a.completedAt < b.completedAt)
106
+ return 1;
107
+ if (a.completedAt > b.completedAt)
108
+ return -1;
109
+ return 0;
110
+ });
111
+ return picked.slice(0, maxDemos).map((exp) => ({
112
+ task: exp.task.trim(),
113
+ output: exp.output.trim(),
114
+ score: exp.feedback.score,
115
+ taskType: exp.taskType || "general",
116
+ }));
117
+ }
118
+ // ─── Rendering ──────────────────────────────────────────────────────────────
119
+ /**
120
+ * Strip the demo-section marker literals out of quoted demo text. A past
121
+ * output that itself contains `<!-- darwin:demos:end -->` (e.g. an agent
122
+ * writing ABOUT Darwin) would otherwise plant an early end-marker inside the
123
+ * section — the next refresh cycle's lazy marker-to-marker match would then
124
+ * cut at the wrong span and leave half the old section dangling in the prompt.
125
+ */
126
+ function stripMarkerLiterals(text) {
127
+ return text.split(DEMO_SECTION_START).join("").split(DEMO_SECTION_END).join("");
128
+ }
129
+ /** Truncate at the last sentence/newline boundary within `maxLength`. */
130
+ function truncateAtSentenceBoundary(text, maxLength) {
131
+ if (text.length <= maxLength)
132
+ return text;
133
+ const truncated = text.slice(0, maxLength);
134
+ const lastPeriod = truncated.lastIndexOf(".");
135
+ const lastNewline = truncated.lastIndexOf("\n");
136
+ const cutPoint = Math.max(lastPeriod, lastNewline);
137
+ // Only honour the boundary when it keeps a meaningful chunk (> 40%).
138
+ const kept = cutPoint > maxLength * 0.4 ? truncated.slice(0, cutPoint + 1) : truncated;
139
+ return `${kept.trimEnd()} [...]`;
140
+ }
141
+ /**
142
+ * Render demo candidates as a marker-delimited prompt section.
143
+ *
144
+ * Returns an empty string for an empty demo list so callers can treat
145
+ * "nothing to inject" uniformly.
146
+ */
147
+ export function buildDemoSection(demos, options = {}) {
148
+ if (demos.length === 0)
149
+ return "";
150
+ const maxTask = clampOption(options.maxTaskChars, 20, DEFAULT_DEMO_TASK_CHARS);
151
+ const maxOutput = clampOption(options.maxOutputChars, 80, DEFAULT_DEMO_OUTPUT_CHARS);
152
+ const blocks = demos.map((demo, i) => {
153
+ const task = truncateAtSentenceBoundary(stripMarkerLiterals(demo.task), maxTask);
154
+ const excerpt = truncateAtSentenceBoundary(stripMarkerLiterals(demo.output), maxOutput);
155
+ return (`### Demonstration ${i + 1} — task type "${demo.taskType}" (scored ${demo.score}/10)\n` +
156
+ `Task: ${task}\n` +
157
+ `Response excerpt:\n"""\n${excerpt}\n"""`);
158
+ });
159
+ return [DEMO_SECTION_START, DEMO_SECTION_INTRO, ...blocks, DEMO_SECTION_END].join("\n\n");
160
+ }
161
+ // ─── Application ────────────────────────────────────────────────────────────
162
+ /** Regex matching one marker-delimited demo section (including markers). */
163
+ const DEMO_SECTION_PATTERN = new RegExp(`${DEMO_SECTION_START.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${DEMO_SECTION_END.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`);
164
+ /**
165
+ * Apply a rendered demo section to a prompt.
166
+ *
167
+ * If the prompt already contains a marker-delimited demo section it is
168
+ * REPLACED in place (demos stay fresh, never stack); otherwise the section is
169
+ * appended after a blank line. An empty `section` returns the prompt with any
170
+ * existing demo section stripped — passing "no demos" acts as removal.
171
+ *
172
+ * The replacement uses a FUNCTION replacer: with a string replacer,
173
+ * `$&` / `$'` / `` $` `` / `$$` inside the section (an agent output quoting
174
+ * JS-regex or shell docs contains exactly these) would be interpreted as
175
+ * replacement patterns and garble the prompt on every refresh cycle.
176
+ */
177
+ export function applyDemoSection(prompt, section) {
178
+ if (section === "")
179
+ return stripDemoSection(prompt);
180
+ if (DEMO_SECTION_PATTERN.test(prompt)) {
181
+ return prompt.replace(DEMO_SECTION_PATTERN, () => section);
182
+ }
183
+ const trimmed = prompt.replace(/\s+$/, "");
184
+ return `${trimmed}\n\n${section}`;
185
+ }
186
+ /**
187
+ * Remove the marker-delimited demo section (if any), collapsing the blank
188
+ * line that {@link applyDemoSection} inserted. Prompts without a section are
189
+ * returned unchanged.
190
+ */
191
+ export function stripDemoSection(prompt) {
192
+ if (!DEMO_SECTION_PATTERN.test(prompt))
193
+ return prompt;
194
+ return prompt.replace(DEMO_SECTION_PATTERN, "").replace(/\n{3,}/g, "\n\n").replace(/\s+$/, "");
195
+ }
196
+ //# sourceMappingURL=demos.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demos.js","sourceRoot":"","sources":["../../../src/evolution/demos.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAqDH,+EAA+E;AAE/E,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AACnC,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAC9C,MAAM,CAAC,MAAM,6BAA6B,GAAG,GAAG,CAAC;AACjD,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAC3C,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAE7C,uEAAuE;AACvE,MAAM,CAAC,MAAM,kBAAkB,GAAG,6BAA6B,CAAC;AAChE,kBAAkB;AAClB,MAAM,CAAC,MAAM,gBAAgB,GAAG,2BAA2B,CAAC;AAE5D,MAAM,kBAAkB,GACtB,qBAAqB;IACrB,sEAAsE;IACtE,0EAA0E;IAC1E,oEAAoE,CAAC;AAEvE,+EAA+E;AAE/E,wDAAwD;AACxD,SAAS,WAAW,CAAC,KAAc,EAAE,GAAW,EAAE,QAAgB;IAChE,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,GAAG;QACxE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QACnB,CAAC,CAAC,QAAQ,CAAC;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAClC,WAA4C,EAC5C,UAAgC,EAAE;IAElC,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,iBAAiB,CAAC,CAAC;IACrE,MAAM,SAAS,GACb,OAAO,OAAO,CAAC,cAAc,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,cAAc,CAAC;QACnF,CAAC,CAAC,OAAO,CAAC,cAAc;QACxB,CAAC,CAAC,4BAA4B,CAAC;IACnC,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,EAAE,6BAA6B,CAAC,CAAC;IAEvF,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE;QAC3C,IAAI,CAAC,GAAG,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAC/B,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC;QAClC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,SAAS;YAAE,OAAO,KAAK,CAAC;QAC5F,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QAC1B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,QAAQ;YAAE,OAAO,KAAK,CAAC;QAChF,OAAO,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,2EAA2E;IAC3E,MAAM,WAAW,GAAG,IAAI,GAAG,EAA4B,CAAC;IACxD,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,IAAI,SAAS,CAAC;QACtC,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAC1B,SAAS;QACX,CAAC;QACD,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAS,CAAC,KAAK,CAAC;QACrC,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAS,CAAC,KAAK,CAAC;QAC3C,IACE,QAAQ,GAAG,QAAQ;YACnB,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC,EAClE,CAAC;YACD,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACrD,MAAM,UAAU,GAAG,CAAC,CAAC,QAAS,CAAC,KAAK,GAAG,CAAC,CAAC,QAAS,CAAC,KAAK,CAAC;QACzD,IAAI,UAAU,KAAK,CAAC;YAAE,OAAO,UAAU,CAAC;QACxC,4DAA4D;QAC5D,IAAI,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW;YAAE,OAAO,CAAC,CAAC;QAC5C,IAAI,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW;YAAE,OAAO,CAAC,CAAC,CAAC;QAC7C,OAAO,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC7C,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE;QACrB,MAAM,EAAE,GAAG,CAAC,MAAO,CAAC,IAAI,EAAE;QAC1B,KAAK,EAAE,GAAG,CAAC,QAAS,CAAC,KAAK;QAC1B,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,SAAS;KACpC,CAAC,CAAC,CAAC;AACN,CAAC;AAED,+EAA+E;AAE/E;;;;;;GAMG;AACH,SAAS,mBAAmB,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAClF,CAAC;AAED,yEAAyE;AACzE,SAAS,0BAA0B,CAAC,IAAY,EAAE,SAAiB;IACjE,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,IAAI,CAAC;IAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC3C,MAAM,UAAU,GAAG,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IACnD,qEAAqE;IACrE,MAAM,IAAI,GAAG,QAAQ,GAAG,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACvF,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC;AACnC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAAmC,EACnC,UAA6B,EAAE;IAE/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,EAAE,uBAAuB,CAAC,CAAC;IAC/E,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,EAAE,yBAAyB,CAAC,CAAC;IAErF,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QACnC,MAAM,IAAI,GAAG,0BAA0B,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;QACjF,MAAM,OAAO,GAAG,0BAA0B,CAAC,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,CAAC;QACxF,OAAO,CACL,qBAAqB,CAAC,GAAG,CAAC,iBAAiB,IAAI,CAAC,QAAQ,aAAa,IAAI,CAAC,KAAK,QAAQ;YACvF,SAAS,IAAI,IAAI;YACjB,2BAA2B,OAAO,OAAO,CAC1C,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,kBAAkB,EAAE,kBAAkB,EAAE,GAAG,MAAM,EAAE,gBAAgB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC5F,CAAC;AAED,+EAA+E;AAE/E,4EAA4E;AAC5E,MAAM,oBAAoB,GAAG,IAAI,MAAM,CACrC,GAAG,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,aAAa,gBAAgB,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,EAAE,CACnI,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,OAAe;IAC9D,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACpD,IAAI,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACtC,OAAO,MAAM,CAAC,OAAO,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC3C,OAAO,GAAG,OAAO,OAAO,OAAO,EAAE,CAAC;AACpC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IACtD,OAAO,MAAM,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACjG,CAAC"}
@@ -39,11 +39,11 @@ export declare function setEvolutionEnabled(memory: MemoryProvider, agentName: s
39
39
  * ({@link DarwinState.evolutionConfigOverrides}) merged ON TOP, then any
40
40
  * in-this-process CLI override merged last (e.g. `darwin run … --gepa`).
41
41
  *
42
- * Only the five advanced flags are overridable; every other field
43
- * (`enabled`, `metrics`, `minRuns`, …) is taken verbatim from the static
44
- * config. Returns `undefined` when the agent has no `evolution` block AND no
45
- * persisted/CLI override would create one — overriding a flag on an agent that
46
- * never opted into evolution is meaningless.
42
+ * Only the advanced flags in {@link OVERRIDE_KEYS} are overridable; every
43
+ * other field (`enabled`, `metrics`, `minRuns`, …) is taken verbatim from the
44
+ * static config. Returns `undefined` when the agent has no `evolution` block
45
+ * AND no persisted/CLI override would create one — overriding a flag on an
46
+ * agent that never opted into evolution is meaningless.
47
47
  *
48
48
  * Read defensively: undefined override values are skipped so they never clobber
49
49
  * a static default with `undefined`.
@@ -1 +1 @@
1
- {"version":3,"file":"enabled-state.d.ts","sourceRoot":"","sources":["../../../src/evolution/enabled-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,eAAe,EACf,uBAAuB,EACvB,cAAc,EACf,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC,GAC3C,OAAO,CAUT;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,CAQf;AAaD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,0BAA0B,CAAC,EACpD,WAAW,CAAC,EAAE,uBAAuB,GACpC,eAAe,GAAG,SAAS,CA8B7B;AAED;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CASf"}
1
+ {"version":3,"file":"enabled-state.d.ts","sourceRoot":"","sources":["../../../src/evolution/enabled-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,eAAe,EACf,uBAAuB,EACvB,cAAc,EACf,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC,GAC3C,OAAO,CAUT;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,CAQf;AAeD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,0BAA0B,CAAC,EACpD,WAAW,CAAC,EAAE,uBAAuB,GACpC,eAAe,GAAG,SAAS,CAgC7B;AAED;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CASf"}
@@ -58,6 +58,8 @@ const OVERRIDE_KEYS = [
58
58
  'paretoGate',
59
59
  'useCoverage',
60
60
  'reflectionModel',
61
+ 'useDemos',
62
+ 'candidateSelection',
61
63
  ];
62
64
  /**
63
65
  * Resolve the effective {@link EvolutionConfig} for an agent: the static
@@ -65,11 +67,11 @@ const OVERRIDE_KEYS = [
65
67
  * ({@link DarwinState.evolutionConfigOverrides}) merged ON TOP, then any
66
68
  * in-this-process CLI override merged last (e.g. `darwin run … --gepa`).
67
69
  *
68
- * Only the five advanced flags are overridable; every other field
69
- * (`enabled`, `metrics`, `minRuns`, …) is taken verbatim from the static
70
- * config. Returns `undefined` when the agent has no `evolution` block AND no
71
- * persisted/CLI override would create one — overriding a flag on an agent that
72
- * never opted into evolution is meaningless.
70
+ * Only the advanced flags in {@link OVERRIDE_KEYS} are overridable; every
71
+ * other field (`enabled`, `metrics`, `minRuns`, …) is taken verbatim from the
72
+ * static config. Returns `undefined` when the agent has no `evolution` block
73
+ * AND no persisted/CLI override would create one — overriding a flag on an
74
+ * agent that never opted into evolution is meaningless.
73
75
  *
74
76
  * Read defensively: undefined override values are skipped so they never clobber
75
77
  * a static default with `undefined`.
@@ -95,6 +97,9 @@ export function resolveEvolutionConfig(agent, state, cliOverride) {
95
97
  if (key === 'reflectionModel') {
96
98
  resolved.reflectionModel = value;
97
99
  }
100
+ else if (key === 'candidateSelection') {
101
+ resolved.candidateSelection = value;
102
+ }
98
103
  else {
99
104
  resolved[key] = value;
100
105
  }
@@ -1 +1 @@
1
- {"version":3,"file":"enabled-state.js","sourceRoot":"","sources":["../../../src/evolution/enabled-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAsB,EACtB,KAA4C;IAE5C,MAAM,SAAS,GAAG,KAAK,CAAC,gBAAgB,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvD,IAAI,OAAO,SAAS,KAAK,SAAS,EAAE,CAAC;QACnC,0EAA0E;QAC1E,wEAAwE;QACxE,yEAAyE;QACzE,2EAA2E;QAC3E,OAAO,SAAS,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC;IACpD,CAAC;IACD,OAAO,KAAK,CAAC,SAAS,EAAE,OAAO,IAAI,KAAK,CAAC;AAC3C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAsB,EACtB,SAAiB,EACjB,OAAgB;IAEhB,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,EAAE;QACjC,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;YAC5B,KAAK,CAAC,gBAAgB,GAAG,EAAE,CAAC;QAC9B,CAAC;QACD,KAAK,CAAC,gBAAgB,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC;QAC5C,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAED,uEAAuE;AAEvE,yDAAyD;AACzD,MAAM,aAAa,GAAG;IACpB,SAAS;IACT,UAAU;IACV,YAAY;IACZ,aAAa;IACb,iBAAiB;CACT,CAAC;AAEX;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,sBAAsB,CACpC,KAAsB,EACtB,KAAoD,EACpD,WAAqC;IAErC,MAAM,SAAS,GAAG,KAAK,CAAC,wBAAwB,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/D,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC;IAE7B,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,WAAW,EAAE,CAAC;QACxC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,2EAA2E;IAC3E,2EAA2E;IAC3E,6EAA6E;IAC7E,MAAM,QAAQ,GAAoB,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAE1E,KAAK,MAAM,KAAK,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;QAC7C,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;YAChC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;YACzB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,oEAAoE;gBACpE,kCAAkC;gBAClC,IAAI,GAAG,KAAK,iBAAiB,EAAE,CAAC;oBAC9B,QAAQ,CAAC,eAAe,GAAG,KAAe,CAAC;gBAC7C,CAAC;qBAAM,CAAC;oBACN,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAgB,CAAC;gBACnC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,MAAsB,EACtB,SAAiB,EACjB,OAAgC;IAEhC,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,EAAE;QACjC,IAAI,CAAC,KAAK,CAAC,wBAAwB,EAAE,CAAC;YACpC,KAAK,CAAC,wBAAwB,GAAG,EAAE,CAAC;QACtC,CAAC;QACD,MAAM,QAAQ,GAAG,KAAK,CAAC,wBAAwB,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QACjE,KAAK,CAAC,wBAAwB,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC;QACxE,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"enabled-state.js","sourceRoot":"","sources":["../../../src/evolution/enabled-state.ts"],"names":[],"mappings":"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"}
@@ -58,6 +58,13 @@ interface DarwinLoopDeps {
58
58
  * (only used when `embed` is set). Default 0.82.
59
59
  */
60
60
  alignmentSimilarityThreshold?: number;
61
+ /**
62
+ * v0.10.0 — Random source in [0, 1) for the stochastic parent-selection
63
+ * strategies (`candidateSelection: 'pareto' | 'epsilon-greedy'`). Injected
64
+ * for deterministic tests; default `Math.random`. Never consulted on the
65
+ * default `'active'` path.
66
+ */
67
+ rng?: () => number;
61
68
  }
62
69
  export declare class DarwinLoop {
63
70
  private memory;
@@ -70,6 +77,7 @@ export declare class DarwinLoop {
70
77
  private gepa?;
71
78
  private embed?;
72
79
  private alignmentSimilarityThreshold?;
80
+ private rng?;
73
81
  constructor(deps: DarwinLoopDeps);
74
82
  /**
75
83
  * Called AFTER every agent run. Drives the evolution cycle.
@@ -173,6 +181,34 @@ export declare class DarwinLoop {
173
181
  * v0.7.0 — Merge cadence (every K-th cycle). Default 3, clamped ≥ 1.
174
182
  */
175
183
  private mergeEveryK;
184
+ /**
185
+ * v0.10.0 — Demo-injection cadence (every K-th cycle). Default 4, clamped
186
+ * ≥ 1. Deliberately offset from the merge default (3) so the two
187
+ * non-reflective challenger sources don't collide on the same cycles.
188
+ */
189
+ private demoEveryK;
190
+ /**
191
+ * v0.10.0 — Build a SIMBA-style demo challenger: current prompt + a
192
+ * marker-delimited "Demonstrations" section harvested from this agent's
193
+ * highest-scoring past runs. Pure selection + rendering — no LLM call.
194
+ *
195
+ * Returns `null` (→ caller falls through to GEPA/legacy generation) when
196
+ * no run qualifies (score/threshold/length filters) or when the rendered
197
+ * demo set is byte-identical to what the prompt already carries — an A/B
198
+ * test of a version against itself would be pointless.
199
+ */
200
+ private tryDemoVariant;
201
+ /**
202
+ * v0.10.0 — Scored version history for parent selection AND merge: every
203
+ * prompt version that has text and at least one run's worth of averaged
204
+ * metrics, as {@link ScoredVariant}s. One getAverageMetrics
205
+ * (→ loadExperiments) call per version. O(N) backend round-trips, but N is
206
+ * the agent's prompt-version count (≤ ~20 in practice) and this only runs
207
+ * on selection/merge cadences, so it is cheap — same pattern handleABTest
208
+ * already uses for the Pareto gate. (Extracted from tryMergeVariant,
209
+ * behaviour unchanged.)
210
+ */
211
+ private buildScoredHistory;
176
212
  /**
177
213
  * v0.7.0 — GEPA system-aware MERGE (paper Appendix-D). Builds scored
178
214
  * variants from this agent's prompt-version history (each version's prompt
@@ -1 +1 @@
1
- {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../../src/evolution/loop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../../src/evolution/loop.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,8 @@ import { notifyABTestComplete, notifyEvolutionStarted, notifyRollback } from './
13
13
  import { epochShuffledMinibatch } from './optimizer-gepa.js';
14
14
  import { checkAlignmentPreservation, checkAlignmentPreservationSemantic } from './alignment.js';
15
15
  import { dominatesEpsilon, paretoSelect, DARWIN_DEFAULT_OBJECTIVES } from './pareto.js';
16
+ import { selectDemoCandidates, buildDemoSection, applyDemoSection } from './demos.js';
17
+ import { selectParentVariant } from './selection.js';
16
18
  // ─── Validation Constants ─────────────────────────────
17
19
  /** Default minimum output length (overridden by agent.evolution.minOutputLength) */
18
20
  const DEFAULT_MIN_VALID_OUTPUT = 2000;
@@ -30,6 +32,7 @@ export class DarwinLoop {
30
32
  gepa;
31
33
  embed;
32
34
  alignmentSimilarityThreshold;
35
+ rng;
33
36
  constructor(deps) {
34
37
  this.memory = deps.memory;
35
38
  this.tracker = deps.tracker;
@@ -41,6 +44,7 @@ export class DarwinLoop {
41
44
  this.gepa = deps.gepa;
42
45
  this.embed = deps.embed;
43
46
  this.alignmentSimilarityThreshold = deps.alignmentSimilarityThreshold;
47
+ this.rng = deps.rng;
44
48
  }
45
49
  /**
46
50
  * Called AFTER every agent run. Drives the evolution cycle.
@@ -250,7 +254,33 @@ export class DarwinLoop {
250
254
  // optimizer so the loop never stalls.
251
255
  let newPromptText = null;
252
256
  let generatedBy = 'legacy';
253
- if (this.agent?.evolution?.useGepa === true && this.gepa) {
257
+ // ── v0.10.0: SIMBA-style demo injection (opt-in, zero LLM cost) ──
258
+ // On every demoEveryK-th cycle, build a challenger by appending (or
259
+ // refreshing) a "Demonstrations" section harvested from the agent's own
260
+ // highest-scoring past runs. Independent of useGepa — no reflector is
261
+ // involved. The demo prompt runs the same alignment guard and enters the
262
+ // same A/B test as any mutation; when demos don't help, the incumbent
263
+ // wins. When the demo set is unchanged since the last injection the path
264
+ // yields no challenger (no-op) and falls through to GEPA/legacy.
265
+ if (this.agent?.evolution?.useDemos === true) {
266
+ const epoch = this.versionInt(activePrompt.version);
267
+ if (epoch > 0 && epoch % this.demoEveryK() === 0) {
268
+ const demoPrompt = await this.tryDemoVariant(agent, activePrompt.promptText);
269
+ if (demoPrompt !== null) {
270
+ const guarded = await this.runAlignmentGuard(activePrompt.promptText, demoPrompt);
271
+ if (guarded !== null) {
272
+ newPromptText = guarded;
273
+ generatedBy = 'demos';
274
+ }
275
+ else {
276
+ // Mirrors the merge-path breadcrumb: a consistently guard-failing
277
+ // demo section should be visible, not silently skipped forever.
278
+ console.warn(`[darwin] demo variant for "${agent}" failed the alignment guard, falling through.`);
279
+ }
280
+ }
281
+ }
282
+ }
283
+ if (newPromptText === null && this.agent?.evolution?.useGepa === true && this.gepa) {
254
284
  // Epoch = the integer of the active prompt version (v1→1, v12→12). It
255
285
  // advances by one each evolution cycle, so the epoch-shuffled minibatch
256
286
  // rotates which feedback subset the reflector sees per cycle, and the
@@ -273,10 +303,11 @@ export class DarwinLoop {
273
303
  promptText: newPromptText,
274
304
  createdAt: new Date().toISOString(),
275
305
  parentVersion: activePrompt.version,
276
- // Only tag the change reason with the generator when GEPA was opted in —
277
- // keeps the stored `changeReason` byte-for-byte identical for legacy-only
306
+ // Only tag the change reason with the generator when a non-legacy
307
+ // challenger source was opted in (GEPA v0.6.0 / demos v0.10.0) — keeps
308
+ // the stored `changeReason` byte-for-byte identical for legacy-only
278
309
  // agents (v0.6.0 review Finding 8).
279
- changeReason: this.agent?.evolution?.useGepa
310
+ changeReason: this.agent?.evolution?.useGepa || this.agent?.evolution?.useDemos
280
311
  ? `[${generatedBy}] ${this.buildChangeReason(detectedPatterns)}`
281
312
  : this.buildChangeReason(detectedPatterns),
282
313
  active: false, // Not active yet — going into A/B test
@@ -305,7 +336,9 @@ export class DarwinLoop {
305
336
  result.promptEvolved = true;
306
337
  result.abTestStarted = true;
307
338
  result.newVersion = newVersion;
308
- const genLabel = this.agent?.evolution?.useGepa ? ` via ${generatedBy}` : '';
339
+ const genLabel = this.agent?.evolution?.useGepa || this.agent?.evolution?.useDemos
340
+ ? ` via ${generatedBy}`
341
+ : '';
309
342
  result.message = `New prompt ${newVersion} generated${genLabel}. A/B test started: ${activePrompt.version} vs ${newVersion} (minRuns: ${dynamicMinRuns}).`;
310
343
  // Notify via Telegram (non-blocking)
311
344
  notifyEvolutionStarted(this.notifications, agent, activePrompt.version, newVersion, this.buildChangeReason(detectedPatterns)).catch(() => { });
@@ -554,10 +587,31 @@ export class DarwinLoop {
554
587
  // currently-active prompt. Falls back to the active prompt when fewer than
555
588
  // two versions carry per-task-type data (selectCoverageParent → null).
556
589
  let parentPrompt = currentPrompt;
590
+ let parentChosen = false;
557
591
  if (this.agent?.evolution?.useCoverage === true) {
558
592
  const coverageParent = await this.selectCoverageParent(agentName);
559
593
  if (coverageParent !== null) {
560
594
  parentPrompt = coverageParent;
595
+ parentChosen = true;
596
+ }
597
+ }
598
+ // v0.10.0: GEPA candidate_selection_strategy parity (opt-in via
599
+ // evolution.candidateSelection). Pick the reflection parent from the
600
+ // agent's SCORED version history — 'best' (current_best), 'pareto'
601
+ // (uniform sample from the non-dominated front), or 'epsilon-greedy'
602
+ // (explore/exploit). Coverage selection (the more specific GEPA
603
+ // Algorithm 2 selector) takes precedence when it found a parent; this
604
+ // strategy is the fallback for that cycle. 'active'/unset keeps the
605
+ // historical reflect-from-active-prompt behaviour byte-for-byte.
606
+ const strategy = this.agent?.evolution?.candidateSelection;
607
+ if (!parentChosen && strategy !== undefined && strategy !== 'active') {
608
+ const scored = await this.buildScoredHistory(agentName);
609
+ const chosen = selectParentVariant(scored, strategy, {
610
+ epsilon: this.agent?.evolution?.explorationEpsilon,
611
+ rng: this.rng,
612
+ });
613
+ if (chosen !== null) {
614
+ parentPrompt = chosen.prompt;
561
615
  }
562
616
  }
563
617
  // v0.7.0: pull the configurable feedback window (default 15, was 5).
@@ -625,6 +679,64 @@ export class DarwinLoop {
625
679
  return Math.floor(k);
626
680
  return 3;
627
681
  }
682
+ /**
683
+ * v0.10.0 — Demo-injection cadence (every K-th cycle). Default 4, clamped
684
+ * ≥ 1. Deliberately offset from the merge default (3) so the two
685
+ * non-reflective challenger sources don't collide on the same cycles.
686
+ */
687
+ demoEveryK() {
688
+ const k = this.agent?.evolution?.demoEveryK;
689
+ if (typeof k === 'number' && Number.isFinite(k) && k >= 1)
690
+ return Math.floor(k);
691
+ return 4;
692
+ }
693
+ /**
694
+ * v0.10.0 — Build a SIMBA-style demo challenger: current prompt + a
695
+ * marker-delimited "Demonstrations" section harvested from this agent's
696
+ * highest-scoring past runs. Pure selection + rendering — no LLM call.
697
+ *
698
+ * Returns `null` (→ caller falls through to GEPA/legacy generation) when
699
+ * no run qualifies (score/threshold/length filters) or when the rendered
700
+ * demo set is byte-identical to what the prompt already carries — an A/B
701
+ * test of a version against itself would be pointless.
702
+ */
703
+ async tryDemoVariant(agentName, currentPrompt) {
704
+ const experiments = await this.memory.loadExperiments(agentName);
705
+ const demos = selectDemoCandidates(experiments, {
706
+ maxDemos: this.agent?.evolution?.maxDemos,
707
+ scoreThreshold: this.agent?.evolution?.demoScoreThreshold,
708
+ });
709
+ if (demos.length === 0)
710
+ return null;
711
+ const section = buildDemoSection(demos);
712
+ const withDemos = applyDemoSection(currentPrompt, section);
713
+ if (withDemos === currentPrompt)
714
+ return null;
715
+ return withDemos;
716
+ }
717
+ /**
718
+ * v0.10.0 — Scored version history for parent selection AND merge: every
719
+ * prompt version that has text and at least one run's worth of averaged
720
+ * metrics, as {@link ScoredVariant}s. One getAverageMetrics
721
+ * (→ loadExperiments) call per version. O(N) backend round-trips, but N is
722
+ * the agent's prompt-version count (≤ ~20 in practice) and this only runs
723
+ * on selection/merge cadences, so it is cheap — same pattern handleABTest
724
+ * already uses for the Pareto gate. (Extracted from tryMergeVariant,
725
+ * behaviour unchanged.)
726
+ */
727
+ async buildScoredHistory(agentName) {
728
+ const versions = await this.memory.getAllPromptVersions(agentName);
729
+ const scored = [];
730
+ for (const v of versions) {
731
+ if (!v.promptText)
732
+ continue;
733
+ const metrics = await this.tracker.getAverageMetrics(agentName, v.version);
734
+ if (Object.keys(metrics).length === 0)
735
+ continue; // no runs for this version
736
+ scored.push({ id: v.version, prompt: v.promptText, metrics });
737
+ }
738
+ return scored;
739
+ }
628
740
  /**
629
741
  * v0.7.0 — GEPA system-aware MERGE (paper Appendix-D). Builds scored
630
742
  * variants from this agent's prompt-version history (each version's prompt
@@ -641,20 +753,7 @@ export class DarwinLoop {
641
753
  async tryMergeVariant(agentName) {
642
754
  if (!this.gepa)
643
755
  return null;
644
- const versions = await this.memory.getAllPromptVersions(agentName);
645
- const scored = [];
646
- // One getAverageMetrics (→ loadExperiments) call per version. O(N) backend
647
- // round-trips, but N is the agent's prompt-version count (≤ ~20 in
648
- // practice) and this only runs on the merge cadence, so it is cheap — same
649
- // pattern handleABTest already uses for the Pareto gate.
650
- for (const v of versions) {
651
- if (!v.promptText)
652
- continue;
653
- const metrics = await this.tracker.getAverageMetrics(agentName, v.version);
654
- if (Object.keys(metrics).length === 0)
655
- continue; // no runs for this version
656
- scored.push({ id: v.version, prompt: v.promptText, metrics });
657
- }
756
+ const scored = await this.buildScoredHistory(agentName);
658
757
  if (scored.length < 2)
659
758
  return null; // need two parents to merge
660
759
  // Two best Pareto-front members (distinct versions, scalarised tie-break).