open-agents-ai 0.43.0 → 0.44.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.
- package/README.md +43 -1
- package/dist/index.js +578 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,6 +37,7 @@ An autonomous multi-turn tool-calling agent that reads your code, makes changes,
|
|
|
37
37
|
- **Sub-agent delegation** — spawn independent agents for parallel workstreams
|
|
38
38
|
- **Ralph Loop** — iterative task execution that keeps retrying until completion criteria are met
|
|
39
39
|
- **Dream Mode** — creative idle exploration modeled after real sleep architecture (NREM→REM cycles)
|
|
40
|
+
- **Autoresearch Swarm** — 5-agent GPU experiment loop during REM sleep: Researcher, Monitor, Evaluator, Critic, Flow Maintainer autonomously run ML training experiments, keep improvements, discard regressions
|
|
40
41
|
- **Live Listen** — bidirectional voice communication with real-time Whisper transcription
|
|
41
42
|
- **Neural TTS** — hear what the agent is doing via GLaDOS or Overwatch ONNX voices, with personality-driven expressiveness
|
|
42
43
|
- **Personality Core** — SAC framework-based style control (concise/balanced/verbose/pedagogical) that shapes agent response depth, voice expressiveness, and system prompt behavior
|
|
@@ -293,6 +294,47 @@ Each cycle expands through all four stages then contracts (evaluation, pruning o
|
|
|
293
294
|
|
|
294
295
|
All proposals are indexed in `.oa/dreams/PROPOSAL-INDEX.md` for easy review.
|
|
295
296
|
|
|
297
|
+
### Autoresearch Swarm — 5-Agent GPU Experiment Loop
|
|
298
|
+
|
|
299
|
+
When a GPU is detected and the model tier is "large", the REM stage of Dream Mode activates the **Autoresearch Swarm** instead of the standard multi-agent creative exploration. This is a 5-agent system inspired by [Karpathy's autoresearch](https://github.com/karpathy/autoresearch) that autonomously runs ML training experiments.
|
|
300
|
+
|
|
301
|
+
The swarm operates in four phases:
|
|
302
|
+
|
|
303
|
+
| Phase | What Happens |
|
|
304
|
+
|-------|-------------|
|
|
305
|
+
| **Phase 0: Load** | Reads autoresearch memory (best config, experiment log, failed approaches, hypothesis queue, architectural insights) + detects GPU specs |
|
|
306
|
+
| **Phase 1: Hypothesis** | Critic generates 5-8 hypotheses; Flow Maintainer plans experiment ordering and round budget |
|
|
307
|
+
| **Phase 2: Experiment** | Sequential rounds (up to 3): Critic pre-screens → Researcher modifies train.py + runs → Monitor watches GPU → Evaluator keeps/discards → Flow Maintainer decides continue/stop |
|
|
308
|
+
| **Phase 3: Summary** | Flow Maintainer writes consolidated summary to memory + dream report to `.oa/dreams/` |
|
|
309
|
+
|
|
310
|
+
#### The 5 Agent Roles
|
|
311
|
+
|
|
312
|
+
| Role | MaxTurns | Temp | Purpose |
|
|
313
|
+
|------|----------|------|---------|
|
|
314
|
+
| **Researcher** | 25 | 0.4 | Modifies train.py, runs experiments via `autoresearch` tool |
|
|
315
|
+
| **Monitor** | 5 | 0.1 | Watches GPU utilization, reports status (detachable between rounds) |
|
|
316
|
+
| **Evaluator** | 12 | 0.3 | Compares results to best val_bpb, calls keep/discard, writes insights to memory |
|
|
317
|
+
| **Critic** | 8 | 0.5 | Generates hypotheses, pre-screens before GPU time is spent |
|
|
318
|
+
| **Flow Maintainer** | 10 | 0.3 | Orchestrates rounds, manages hypothesis queue, writes final summary |
|
|
319
|
+
|
|
320
|
+
#### Bidirectional Memory
|
|
321
|
+
|
|
322
|
+
The swarm maintains persistent memory in `.oa/memory/autoresearch.json` with five keys:
|
|
323
|
+
|
|
324
|
+
- **best_config** — best val_bpb and what train.py changes produced it
|
|
325
|
+
- **experiment_log** — chronological list of experiments with hypotheses, results, and verdicts
|
|
326
|
+
- **architectural_insights** — patterns learned (what architectures work, what doesn't)
|
|
327
|
+
- **failed_approaches** — things NOT to try again (with reasons)
|
|
328
|
+
- **hypothesis_queue** — pending ideas for future experiments
|
|
329
|
+
|
|
330
|
+
Memory flows bidirectionally: the swarm reads all 5 keys at startup (Phase 0) and writes results back after each experiment. The DMN's gather phase naturally discovers autoresearch learnings when searching all memory, and DMN proposals with category `"autoresearch"` execute through the normal agentic loop.
|
|
331
|
+
|
|
332
|
+
#### Monitor Detachability
|
|
333
|
+
|
|
334
|
+
The Monitor agent can be "detached" between experiment rounds by the Flow Maintainer. When detached, the monitor receives a sub-task (e.g., "analyze GPU memory patterns from last 3 runs") instead of its standard watch prompt. This lets the swarm use idle monitoring capacity for useful analysis work.
|
|
335
|
+
|
|
336
|
+
If no GPU is detected, the REM stage falls back to the standard multi-agent creative exploration (Visionary + Pragmatist + Cross-Pollinator + Synthesizer).
|
|
337
|
+
|
|
296
338
|
## Blessed Mode — Infinite Warm Loop
|
|
297
339
|
|
|
298
340
|
`/full-send-bless` activates an infinite warm loop that keeps model weights loaded in VRAM and the agent ready for instant response. The engine sends periodic keep-alive pings to the inference backend (every 2 minutes) to prevent Ollama's automatic model unloading.
|
|
@@ -322,7 +364,7 @@ Inspired by the brain's Default Mode Network (Raichle 2001), the DMN activates d
|
|
|
322
364
|
|
|
323
365
|
Each DMN cycle runs a lightweight LLM agent (15 max turns, temperature 0.4) with read-only file access plus full memory tools. The DMN writes insights back to memory, creating a self-reinforcing knowledge loop.
|
|
324
366
|
|
|
325
|
-
**Task categories**: directive (standing orders), exploration (knowledge gaps), capability (underused tools), maintenance (system health), social (communication)
|
|
367
|
+
**Task categories**: directive (standing orders), exploration (knowledge gaps), capability (underused tools), maintenance (system health), social (communication), autoresearch (autonomous GPU ML experiment loop)
|
|
326
368
|
|
|
327
369
|
**Backoff**: After 3 consecutive cycles with no actionable task, the DMN enters extended rest. A 30-second cooldown between null cycles prevents spin-looping.
|
|
328
370
|
|
package/dist/index.js
CHANGED
|
@@ -23446,6 +23446,31 @@ var init_edit_history = __esm({
|
|
|
23446
23446
|
import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync11, readFileSync as readFileSync19, existsSync as existsSync26, cpSync, rmSync, readdirSync as readdirSync10 } from "node:fs";
|
|
23447
23447
|
import { join as join36, basename as basename12 } from "node:path";
|
|
23448
23448
|
import { execSync as execSync22 } from "node:child_process";
|
|
23449
|
+
function loadAutoresearchMemory(repoRoot) {
|
|
23450
|
+
const memoryPath = join36(repoRoot, ".oa", "memory", "autoresearch.json");
|
|
23451
|
+
if (!existsSync26(memoryPath))
|
|
23452
|
+
return "";
|
|
23453
|
+
try {
|
|
23454
|
+
const raw = readFileSync19(memoryPath, "utf-8");
|
|
23455
|
+
const data = JSON.parse(raw);
|
|
23456
|
+
const sections = [];
|
|
23457
|
+
for (const key of AUTORESEARCH_MEMORY_KEYS) {
|
|
23458
|
+
if (data[key] !== void 0 && data[key] !== null) {
|
|
23459
|
+
const value = typeof data[key] === "string" ? data[key] : JSON.stringify(data[key], null, 2);
|
|
23460
|
+
sections.push(`### ${key}
|
|
23461
|
+
${value}`);
|
|
23462
|
+
}
|
|
23463
|
+
}
|
|
23464
|
+
if (sections.length === 0)
|
|
23465
|
+
return "";
|
|
23466
|
+
return `
|
|
23467
|
+
## AUTORESEARCH MEMORY (from previous experiments)
|
|
23468
|
+
|
|
23469
|
+
${sections.join("\n\n")}`;
|
|
23470
|
+
} catch {
|
|
23471
|
+
return "";
|
|
23472
|
+
}
|
|
23473
|
+
}
|
|
23449
23474
|
function adaptTool(tool) {
|
|
23450
23475
|
return {
|
|
23451
23476
|
name: tool.name,
|
|
@@ -23584,14 +23609,130 @@ function renderDreamEnd(state) {
|
|
|
23584
23609
|
|
|
23585
23610
|
`);
|
|
23586
23611
|
}
|
|
23587
|
-
|
|
23612
|
+
function renderSwarmPhase(phase, description) {
|
|
23613
|
+
const phaseLabels = ["Load", "Hypothesis", "Experiment", "Summary"];
|
|
23614
|
+
const label = phaseLabels[phase] ?? `Phase ${phase}`;
|
|
23615
|
+
process.stdout.write(`
|
|
23616
|
+
${c2.yellow("\u2B21")} ${c2.bold(`Swarm Phase ${phase}: ${label}`)} ${c2.dim(`\u2014 ${description}`)}
|
|
23617
|
+
`);
|
|
23618
|
+
}
|
|
23619
|
+
function renderSwarmExperiment(round, total, hypothesis) {
|
|
23620
|
+
const truncated = hypothesis.length > 80 ? hypothesis.slice(0, 77) + "..." : hypothesis;
|
|
23621
|
+
process.stdout.write(`
|
|
23622
|
+
${c2.cyan("\u25C8")} ${c2.bold(`Experiment ${round}/${total}`)} ${c2.dim(truncated)}
|
|
23623
|
+
`);
|
|
23624
|
+
}
|
|
23625
|
+
function renderSwarmComplete(workspace) {
|
|
23626
|
+
const kept = workspace.experimentResults.filter((r) => r.verdict === "keep").length;
|
|
23627
|
+
const discarded = workspace.experimentResults.filter((r) => r.verdict === "discard").length;
|
|
23628
|
+
const best = workspace.bestValBpb === Infinity ? "N/A" : workspace.bestValBpb.toFixed(6);
|
|
23629
|
+
process.stdout.write(`
|
|
23630
|
+
${c2.green("\u2B22")} ${c2.bold("Autoresearch Swarm Complete")}
|
|
23631
|
+
`);
|
|
23632
|
+
process.stdout.write(` Rounds: ${workspace.roundsCompleted} | Kept: ${kept} | Discarded: ${discarded} | Best val_bpb: ${best}
|
|
23633
|
+
`);
|
|
23634
|
+
process.stdout.write(` Report: ${c2.cyan(".oa/dreams/")}
|
|
23635
|
+
`);
|
|
23636
|
+
}
|
|
23637
|
+
var SWARM_ROLE_CONFIG, AutoresearchFileWriteTool, AutoresearchFileEditTool, AUTORESEARCH_MEMORY_KEYS, SLEEP_STAGES, DreamFileWriteTool, DreamFileEditTool, DreamShellTool, DreamEngine;
|
|
23588
23638
|
var init_dream_engine = __esm({
|
|
23589
23639
|
"packages/cli/dist/tui/dream-engine.js"() {
|
|
23590
23640
|
"use strict";
|
|
23591
23641
|
init_dist5();
|
|
23592
23642
|
init_dist2();
|
|
23593
23643
|
init_project_context();
|
|
23644
|
+
init_setup();
|
|
23594
23645
|
init_render();
|
|
23646
|
+
SWARM_ROLE_CONFIG = {
|
|
23647
|
+
researcher: { maxTurns: 25, temperature: 0.4 },
|
|
23648
|
+
monitor: { maxTurns: 5, temperature: 0.1 },
|
|
23649
|
+
evaluator: { maxTurns: 12, temperature: 0.3 },
|
|
23650
|
+
critic: { maxTurns: 8, temperature: 0.5 },
|
|
23651
|
+
flow_maintainer: { maxTurns: 10, temperature: 0.3 }
|
|
23652
|
+
};
|
|
23653
|
+
AutoresearchFileWriteTool = class {
|
|
23654
|
+
autoresearchDir;
|
|
23655
|
+
name = "file_write";
|
|
23656
|
+
description = "Write a file (autoresearch mode: writes confined to .oa/autoresearch/ directory)";
|
|
23657
|
+
parameters = {
|
|
23658
|
+
type: "object",
|
|
23659
|
+
properties: {
|
|
23660
|
+
path: { type: "string", description: "File path (relative to .oa/autoresearch/)" },
|
|
23661
|
+
content: { type: "string", description: "File content to write" }
|
|
23662
|
+
},
|
|
23663
|
+
required: ["path", "content"]
|
|
23664
|
+
};
|
|
23665
|
+
constructor(autoresearchDir) {
|
|
23666
|
+
this.autoresearchDir = autoresearchDir;
|
|
23667
|
+
}
|
|
23668
|
+
async execute(args) {
|
|
23669
|
+
const start = Date.now();
|
|
23670
|
+
const rawPath = String(args["path"] ?? "");
|
|
23671
|
+
const content = String(args["content"] ?? "");
|
|
23672
|
+
if (!rawPath)
|
|
23673
|
+
return { success: false, output: "", error: "path is required", durationMs: Date.now() - start };
|
|
23674
|
+
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/autoresearch") ? join36(this.autoresearchDir, basename12(rawPath)) : join36(this.autoresearchDir, rawPath);
|
|
23675
|
+
if (!targetPath.startsWith(this.autoresearchDir)) {
|
|
23676
|
+
return { success: false, output: "", error: "Autoresearch mode: writes are confined to .oa/autoresearch/", durationMs: Date.now() - start };
|
|
23677
|
+
}
|
|
23678
|
+
try {
|
|
23679
|
+
const dir = join36(targetPath, "..");
|
|
23680
|
+
mkdirSync12(dir, { recursive: true });
|
|
23681
|
+
writeFileSync11(targetPath, content, "utf-8");
|
|
23682
|
+
return { success: true, output: `Wrote ${content.length} bytes to ${rawPath}`, durationMs: Date.now() - start };
|
|
23683
|
+
} catch (err) {
|
|
23684
|
+
return { success: false, output: "", error: String(err), durationMs: Date.now() - start };
|
|
23685
|
+
}
|
|
23686
|
+
}
|
|
23687
|
+
};
|
|
23688
|
+
AutoresearchFileEditTool = class {
|
|
23689
|
+
autoresearchDir;
|
|
23690
|
+
name = "file_edit";
|
|
23691
|
+
description = "Edit a file (autoresearch mode: edits confined to .oa/autoresearch/ directory)";
|
|
23692
|
+
parameters = {
|
|
23693
|
+
type: "object",
|
|
23694
|
+
properties: {
|
|
23695
|
+
path: { type: "string", description: "File path (relative to .oa/autoresearch/)" },
|
|
23696
|
+
old_string: { type: "string", description: "Text to replace" },
|
|
23697
|
+
new_string: { type: "string", description: "Replacement text" }
|
|
23698
|
+
},
|
|
23699
|
+
required: ["path", "old_string", "new_string"]
|
|
23700
|
+
};
|
|
23701
|
+
constructor(autoresearchDir) {
|
|
23702
|
+
this.autoresearchDir = autoresearchDir;
|
|
23703
|
+
}
|
|
23704
|
+
async execute(args) {
|
|
23705
|
+
const start = Date.now();
|
|
23706
|
+
const rawPath = String(args["path"] ?? "");
|
|
23707
|
+
const oldStr = String(args["old_string"] ?? "");
|
|
23708
|
+
const newStr = String(args["new_string"] ?? "");
|
|
23709
|
+
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/autoresearch") ? join36(this.autoresearchDir, basename12(rawPath)) : join36(this.autoresearchDir, rawPath);
|
|
23710
|
+
if (!targetPath.startsWith(this.autoresearchDir)) {
|
|
23711
|
+
return { success: false, output: "", error: "Autoresearch mode: edits are confined to .oa/autoresearch/", durationMs: Date.now() - start };
|
|
23712
|
+
}
|
|
23713
|
+
try {
|
|
23714
|
+
if (!existsSync26(targetPath)) {
|
|
23715
|
+
return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start };
|
|
23716
|
+
}
|
|
23717
|
+
let content = readFileSync19(targetPath, "utf-8");
|
|
23718
|
+
if (!content.includes(oldStr)) {
|
|
23719
|
+
return { success: false, output: "", error: "old_string not found in file", durationMs: Date.now() - start };
|
|
23720
|
+
}
|
|
23721
|
+
content = content.replace(oldStr, newStr);
|
|
23722
|
+
writeFileSync11(targetPath, content, "utf-8");
|
|
23723
|
+
return { success: true, output: `Edited ${rawPath}`, durationMs: Date.now() - start };
|
|
23724
|
+
} catch (err) {
|
|
23725
|
+
return { success: false, output: "", error: String(err), durationMs: Date.now() - start };
|
|
23726
|
+
}
|
|
23727
|
+
}
|
|
23728
|
+
};
|
|
23729
|
+
AUTORESEARCH_MEMORY_KEYS = [
|
|
23730
|
+
"best_config",
|
|
23731
|
+
"experiment_log",
|
|
23732
|
+
"failed_approaches",
|
|
23733
|
+
"hypothesis_queue",
|
|
23734
|
+
"architectural_insights"
|
|
23735
|
+
];
|
|
23595
23736
|
SLEEP_STAGES = [
|
|
23596
23737
|
{ name: "NREM-1", label: "Light Scan", description: "Quick codebase overview, surface observations" },
|
|
23597
23738
|
{ name: "NREM-2", label: "Pattern Detection", description: "Identify recurring patterns, technical debt, gaps" },
|
|
@@ -23772,7 +23913,11 @@ var init_dream_engine = __esm({
|
|
|
23772
23913
|
renderDreamStage(stage.name, stage.label, stage.description);
|
|
23773
23914
|
const startMs = Date.now();
|
|
23774
23915
|
let result;
|
|
23775
|
-
if (stage.name === "REM" && modelTier === "large") {
|
|
23916
|
+
if (stage.name === "REM" && modelTier === "large" && detectSystemSpecs().gpuVramGB > 0) {
|
|
23917
|
+
renderInfo("REM: Autoresearch swarm \u2014 5-agent GPU experiment loop (Researcher + Monitor + Evaluator + Critic + Flow Maintainer)");
|
|
23918
|
+
const swarmResult = await this.runAutoresearchSwarm(cycle, previousFindings, onEvent);
|
|
23919
|
+
result = { summary: swarmResult.summary, turns: 0, toolCalls: 0 };
|
|
23920
|
+
} else if (stage.name === "REM" && modelTier === "large") {
|
|
23776
23921
|
renderInfo("REM: Multi-agent creative mode \u2014 parallel Visionary + Pragmatist + Cross-Pollinator");
|
|
23777
23922
|
const remResult = await this.runMultiAgentREM(cycle, totalCycles, previousFindings, mode === "lucid" ? "full" : "sandboxed", onEvent);
|
|
23778
23923
|
result = { summary: remResult.summary, turns: 0, toolCalls: 0 };
|
|
@@ -23980,6 +24125,433 @@ INSTRUCTIONS:
|
|
|
23980
24125
|
After synthesis, call task_complete with the final prioritized summary.`, toolMode, onEvent);
|
|
23981
24126
|
return synthesisResult;
|
|
23982
24127
|
}
|
|
24128
|
+
// ── Autoresearch Swarm ────────────────────────────────────────────────
|
|
24129
|
+
/**
|
|
24130
|
+
* Run a single swarm sub-agent with role-specific tools and config.
|
|
24131
|
+
* Follows the runBrainRegionAgent() pattern from dmn-engine.ts.
|
|
24132
|
+
*/
|
|
24133
|
+
async runSwarmAgent(role, prompt, workspace, onEvent) {
|
|
24134
|
+
const backend = new OllamaAgenticBackend(this.config.backendUrl, this.config.model, this.config.apiKey);
|
|
24135
|
+
const roleConfig = SWARM_ROLE_CONFIG[role];
|
|
24136
|
+
const modelTier = getModelTier(this.config.model);
|
|
24137
|
+
const runner = new AgenticRunner(backend, {
|
|
24138
|
+
maxTurns: roleConfig.maxTurns,
|
|
24139
|
+
maxTokens: 8192,
|
|
24140
|
+
temperature: roleConfig.temperature,
|
|
24141
|
+
requestTimeoutMs: this.config.timeoutMs,
|
|
24142
|
+
taskTimeoutMs: role === "researcher" ? this.config.timeoutMs * 5 : this.config.timeoutMs * 2,
|
|
24143
|
+
compactionThreshold: modelTier === "small" ? 8e3 : 16e3,
|
|
24144
|
+
modelTier
|
|
24145
|
+
});
|
|
24146
|
+
const tools = this.buildSwarmTools(role, workspace);
|
|
24147
|
+
runner.registerTools(tools);
|
|
24148
|
+
if (onEvent) {
|
|
24149
|
+
runner.onEvent((event) => {
|
|
24150
|
+
const taggedEvent = {
|
|
24151
|
+
...event,
|
|
24152
|
+
content: event.type === "status" ? `[${role}] ${event.content ?? ""}` : event.content
|
|
24153
|
+
};
|
|
24154
|
+
onEvent(taggedEvent);
|
|
24155
|
+
});
|
|
24156
|
+
}
|
|
24157
|
+
const result = await runner.run(prompt, `Swarm role: ${role}. Working directory: ${this.repoRoot}`);
|
|
24158
|
+
return result.summary || "{}";
|
|
24159
|
+
}
|
|
24160
|
+
/** Build role-specific tool sets for swarm agents */
|
|
24161
|
+
buildSwarmTools(role, _workspace) {
|
|
24162
|
+
const autoresearchDir = join36(this.repoRoot, ".oa", "autoresearch");
|
|
24163
|
+
const taskComplete = this.createSwarmTaskCompleteTool(role);
|
|
24164
|
+
switch (role) {
|
|
24165
|
+
case "researcher": {
|
|
24166
|
+
const tools = [
|
|
24167
|
+
new FileReadTool(this.repoRoot),
|
|
24168
|
+
new AutoresearchFileEditTool(autoresearchDir),
|
|
24169
|
+
new AutoresearchFileWriteTool(autoresearchDir),
|
|
24170
|
+
new AutoresearchTool(this.repoRoot),
|
|
24171
|
+
new GrepSearchTool(this.repoRoot),
|
|
24172
|
+
new GlobFindTool(this.repoRoot),
|
|
24173
|
+
new MemoryReadTool(this.repoRoot),
|
|
24174
|
+
new MemorySearchTool(this.repoRoot)
|
|
24175
|
+
];
|
|
24176
|
+
return [...tools.map(adaptTool), taskComplete];
|
|
24177
|
+
}
|
|
24178
|
+
case "monitor": {
|
|
24179
|
+
const tools = [
|
|
24180
|
+
new FileReadTool(this.repoRoot),
|
|
24181
|
+
new DreamShellTool(this.repoRoot),
|
|
24182
|
+
// read-only shell
|
|
24183
|
+
new AutoresearchTool(this.repoRoot)
|
|
24184
|
+
// status-only in prompt
|
|
24185
|
+
];
|
|
24186
|
+
return [...tools.map(adaptTool), taskComplete];
|
|
24187
|
+
}
|
|
24188
|
+
case "evaluator": {
|
|
24189
|
+
const tools = [
|
|
24190
|
+
new FileReadTool(this.repoRoot),
|
|
24191
|
+
new AutoresearchTool(this.repoRoot),
|
|
24192
|
+
// results/keep/discard
|
|
24193
|
+
new MemoryReadTool(this.repoRoot),
|
|
24194
|
+
new MemorySearchTool(this.repoRoot),
|
|
24195
|
+
new MemoryWriteTool(this.repoRoot),
|
|
24196
|
+
new GrepSearchTool(this.repoRoot)
|
|
24197
|
+
];
|
|
24198
|
+
return [...tools.map(adaptTool), taskComplete];
|
|
24199
|
+
}
|
|
24200
|
+
case "critic": {
|
|
24201
|
+
const tools = [
|
|
24202
|
+
new FileReadTool(this.repoRoot),
|
|
24203
|
+
new MemoryReadTool(this.repoRoot),
|
|
24204
|
+
new MemorySearchTool(this.repoRoot),
|
|
24205
|
+
new GrepSearchTool(this.repoRoot)
|
|
24206
|
+
];
|
|
24207
|
+
return [...tools.map(adaptTool), taskComplete];
|
|
24208
|
+
}
|
|
24209
|
+
case "flow_maintainer": {
|
|
24210
|
+
const tools = [
|
|
24211
|
+
new MemoryReadTool(this.repoRoot),
|
|
24212
|
+
new MemoryWriteTool(this.repoRoot),
|
|
24213
|
+
new MemorySearchTool(this.repoRoot)
|
|
24214
|
+
];
|
|
24215
|
+
return [...tools.map(adaptTool), taskComplete];
|
|
24216
|
+
}
|
|
24217
|
+
}
|
|
24218
|
+
}
|
|
24219
|
+
createSwarmTaskCompleteTool(role) {
|
|
24220
|
+
return {
|
|
24221
|
+
name: "task_complete",
|
|
24222
|
+
description: `Signal that the ${role} swarm agent is done with its task.`,
|
|
24223
|
+
parameters: {
|
|
24224
|
+
type: "object",
|
|
24225
|
+
properties: {
|
|
24226
|
+
summary: { type: "string", description: "JSON summary of findings/results" }
|
|
24227
|
+
},
|
|
24228
|
+
required: ["summary"]
|
|
24229
|
+
},
|
|
24230
|
+
async execute(args) {
|
|
24231
|
+
return { success: true, output: args["summary"] || "{}" };
|
|
24232
|
+
}
|
|
24233
|
+
};
|
|
24234
|
+
}
|
|
24235
|
+
/**
|
|
24236
|
+
* Run the 5-agent autoresearch swarm — the core orchestrator.
|
|
24237
|
+
*
|
|
24238
|
+
* Phase 0: Load memory + GPU check
|
|
24239
|
+
* Phase 1: Parallel critic + flow maintainer to generate/filter hypothesis queue
|
|
24240
|
+
* Phase 2: Sequential experiment loop (up to 3 rounds)
|
|
24241
|
+
* Phase 3: Consolidated summary to memory + dream report
|
|
24242
|
+
*/
|
|
24243
|
+
async runAutoresearchSwarm(cycleNum, previousFindings, onEvent) {
|
|
24244
|
+
renderSwarmPhase(0, "Loading autoresearch memory + GPU check");
|
|
24245
|
+
const memoryContext = loadAutoresearchMemory(this.repoRoot);
|
|
24246
|
+
const specs = detectSystemSpecs();
|
|
24247
|
+
const gpuInfo = specs.gpuVramGB > 0 ? `GPU: ${specs.gpuName} (${specs.gpuVramGB.toFixed(0)}GB VRAM)` : "GPU: not detected";
|
|
24248
|
+
onEvent?.({
|
|
24249
|
+
type: "status",
|
|
24250
|
+
content: `Autoresearch swarm activating \u2014 ${gpuInfo}`,
|
|
24251
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
24252
|
+
});
|
|
24253
|
+
const workspace = {
|
|
24254
|
+
hypothesisQueue: [],
|
|
24255
|
+
experimentResults: [],
|
|
24256
|
+
monitor: { status: "idle" },
|
|
24257
|
+
memoryContext,
|
|
24258
|
+
bestValBpb: Infinity,
|
|
24259
|
+
roundsCompleted: 0
|
|
24260
|
+
};
|
|
24261
|
+
const baseContext = `AUTORESEARCH SWARM \u2014 Autonomous ML Experiment Loop
|
|
24262
|
+
|
|
24263
|
+
You are part of a 5-agent swarm that iteratively improves a language model
|
|
24264
|
+
training script through hypothesis \u2192 experiment \u2192 evaluate cycles.
|
|
24265
|
+
|
|
24266
|
+
PREVIOUS DREAM FINDINGS:
|
|
24267
|
+
${previousFindings}
|
|
24268
|
+
${memoryContext}
|
|
24269
|
+
|
|
24270
|
+
GPU: ${gpuInfo}
|
|
24271
|
+
Workspace: .oa/autoresearch/`;
|
|
24272
|
+
renderSwarmPhase(1, "Generating hypothesis queue (Critic + Flow Maintainer)");
|
|
24273
|
+
const [criticInit, flowInit] = await Promise.allSettled([
|
|
24274
|
+
this.runSwarmAgent("critic", `${baseContext}
|
|
24275
|
+
|
|
24276
|
+
ROLE: CRITIC \u2014 Hypothesis Generator & Filter
|
|
24277
|
+
You are the adversarial critic. Your job is to:
|
|
24278
|
+
1. Review the current state of experiments (check autoresearch memory above)
|
|
24279
|
+
2. Read train.py in .oa/autoresearch/ to understand current architecture
|
|
24280
|
+
3. Generate 5-8 hypotheses for improving val_bpb (bits per byte)
|
|
24281
|
+
4. For each hypothesis, assess: feasibility, expected impact, risk of regression
|
|
24282
|
+
5. Filter out hypotheses that overlap with failed_approaches in memory
|
|
24283
|
+
|
|
24284
|
+
Output JSON with: { "hypotheses": [{ "id": number, "description": string, "rationale": string, "risk": "low"|"medium"|"high", "expected_impact": string }] }
|
|
24285
|
+
|
|
24286
|
+
Call task_complete with your JSON when done.`, workspace, (event) => onEvent?.({ ...event, content: event.type === "status" ? `[critic] ${event.content ?? ""}` : event.content })),
|
|
24287
|
+
this.runSwarmAgent("flow_maintainer", `${baseContext}
|
|
24288
|
+
|
|
24289
|
+
ROLE: FLOW MAINTAINER \u2014 Experiment Planner
|
|
24290
|
+
You are the flow controller. Your job is to:
|
|
24291
|
+
1. Review autoresearch memory for past experiments and their outcomes
|
|
24292
|
+
2. Identify the current best val_bpb and what changes produced it
|
|
24293
|
+
3. Determine if there's a clear direction of improvement (e.g., architecture changes vs hyperparams)
|
|
24294
|
+
4. Propose an ordering strategy: which types of experiments should run first?
|
|
24295
|
+
5. Set initial experiment budget: how many rounds (1-3) should we attempt?
|
|
24296
|
+
|
|
24297
|
+
Output JSON with: { "strategy": string, "recommended_rounds": number, "priority_order": string[], "stop_conditions": string[] }
|
|
24298
|
+
|
|
24299
|
+
Call task_complete with your JSON when done.`, workspace, (event) => onEvent?.({ ...event, content: event.type === "status" ? `[flow_maintainer] ${event.content ?? ""}` : event.content }))
|
|
24300
|
+
]);
|
|
24301
|
+
const criticOutput = criticInit.status === "fulfilled" ? criticInit.value : "{}";
|
|
24302
|
+
const flowOutput = flowInit.status === "fulfilled" ? flowInit.value : "{}";
|
|
24303
|
+
try {
|
|
24304
|
+
const parsed = JSON.parse(criticOutput.match(/\{[\s\S]*\}/)?.[0] ?? "{}");
|
|
24305
|
+
if (Array.isArray(parsed.hypotheses)) {
|
|
24306
|
+
workspace.hypothesisQueue = parsed.hypotheses.map((h) => h.description ?? `Hypothesis ${h.id ?? 0}`);
|
|
24307
|
+
}
|
|
24308
|
+
} catch {
|
|
24309
|
+
}
|
|
24310
|
+
let maxRounds = 3;
|
|
24311
|
+
try {
|
|
24312
|
+
const parsed = JSON.parse(flowOutput.match(/\{[\s\S]*\}/)?.[0] ?? "{}");
|
|
24313
|
+
if (typeof parsed.recommended_rounds === "number") {
|
|
24314
|
+
maxRounds = Math.min(3, Math.max(1, parsed.recommended_rounds));
|
|
24315
|
+
}
|
|
24316
|
+
} catch {
|
|
24317
|
+
}
|
|
24318
|
+
if (workspace.hypothesisQueue.length === 0) {
|
|
24319
|
+
workspace.hypothesisQueue = [
|
|
24320
|
+
"Increase model depth while reducing width to maintain parameter count",
|
|
24321
|
+
"Adjust learning rate schedule with warmup",
|
|
24322
|
+
"Modify attention mechanism (e.g., grouped query attention)"
|
|
24323
|
+
];
|
|
24324
|
+
}
|
|
24325
|
+
onEvent?.({
|
|
24326
|
+
type: "status",
|
|
24327
|
+
content: `Phase 1 complete: ${workspace.hypothesisQueue.length} hypotheses queued, ${maxRounds} rounds planned`,
|
|
24328
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
24329
|
+
});
|
|
24330
|
+
renderSwarmPhase(2, `Running experiments (up to ${maxRounds} rounds)`);
|
|
24331
|
+
for (let round = 0; round < maxRounds; round++) {
|
|
24332
|
+
if (this.abortController?.signal.aborted)
|
|
24333
|
+
break;
|
|
24334
|
+
if (workspace.hypothesisQueue.length === 0)
|
|
24335
|
+
break;
|
|
24336
|
+
const hypothesis = workspace.hypothesisQueue.shift();
|
|
24337
|
+
renderSwarmExperiment(round + 1, maxRounds, hypothesis);
|
|
24338
|
+
const criticScreen = await this.runSwarmAgent("critic", `${baseContext}
|
|
24339
|
+
|
|
24340
|
+
ROLE: CRITIC \u2014 Pre-screen Hypothesis
|
|
24341
|
+
Quickly evaluate this hypothesis before we spend GPU time on it:
|
|
24342
|
+
|
|
24343
|
+
HYPOTHESIS: ${hypothesis}
|
|
24344
|
+
|
|
24345
|
+
Previous experiment results:
|
|
24346
|
+
${workspace.experimentResults.map((r) => `- ${r.hypothesis}: val_bpb=${r.valBpb}, verdict=${r.verdict}`).join("\n") || "(none yet)"}
|
|
24347
|
+
|
|
24348
|
+
Questions to answer:
|
|
24349
|
+
1. Is this hypothesis likely to improve val_bpb given what we know?
|
|
24350
|
+
2. Does it overlap with any failed approaches?
|
|
24351
|
+
3. Is it safe to implement (won't corrupt the training script)?
|
|
24352
|
+
|
|
24353
|
+
Output JSON: { "approved": boolean, "reason": string, "modifications": string }
|
|
24354
|
+
If not approved, briefly explain why and we'll skip to the next hypothesis.
|
|
24355
|
+
|
|
24356
|
+
Call task_complete with your JSON.`, workspace, (event) => onEvent?.({ ...event, content: event.type === "status" ? `[critic] ${event.content ?? ""}` : event.content }));
|
|
24357
|
+
let approved = true;
|
|
24358
|
+
try {
|
|
24359
|
+
const parsed = JSON.parse(criticScreen.match(/\{[\s\S]*\}/)?.[0] ?? "{}");
|
|
24360
|
+
if (parsed.approved === false) {
|
|
24361
|
+
approved = false;
|
|
24362
|
+
onEvent?.({
|
|
24363
|
+
type: "status",
|
|
24364
|
+
content: `[critic] Rejected hypothesis: ${parsed.reason ?? "no reason given"}`,
|
|
24365
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
24366
|
+
});
|
|
24367
|
+
}
|
|
24368
|
+
} catch {
|
|
24369
|
+
}
|
|
24370
|
+
if (!approved)
|
|
24371
|
+
continue;
|
|
24372
|
+
workspace.monitor.status = "watching";
|
|
24373
|
+
const [researcherResult, monitorResult] = await Promise.allSettled([
|
|
24374
|
+
this.runSwarmAgent("researcher", `${baseContext}
|
|
24375
|
+
|
|
24376
|
+
ROLE: RESEARCHER \u2014 Implement & Run Experiment
|
|
24377
|
+
You are the researcher. Your hypothesis for this round:
|
|
24378
|
+
|
|
24379
|
+
HYPOTHESIS: ${hypothesis}
|
|
24380
|
+
|
|
24381
|
+
INSTRUCTIONS:
|
|
24382
|
+
1. Read the current train.py in .oa/autoresearch/ using file_read
|
|
24383
|
+
2. Modify train.py using file_edit to implement the hypothesis
|
|
24384
|
+
3. Run the experiment using autoresearch(action="run")
|
|
24385
|
+
4. Report the results
|
|
24386
|
+
|
|
24387
|
+
Previous experiments:
|
|
24388
|
+
${workspace.experimentResults.map((r) => `- ${r.hypothesis}: val_bpb=${r.valBpb}, verdict=${r.verdict}`).join("\n") || "(none yet)"}
|
|
24389
|
+
|
|
24390
|
+
Best val_bpb so far: ${workspace.bestValBpb === Infinity ? "N/A (first experiment)" : workspace.bestValBpb.toFixed(6)}
|
|
24391
|
+
|
|
24392
|
+
Be precise with file_edit \u2014 match exact strings from the file. Small, targeted changes are better than large rewrites.
|
|
24393
|
+
|
|
24394
|
+
Call task_complete with JSON: { "val_bpb": number, "changes_made": string, "observations": string }`, workspace, (event) => onEvent?.({ ...event, content: event.type === "status" ? `[researcher] ${event.content ?? ""}` : event.content })),
|
|
24395
|
+
this.runSwarmAgent("monitor", `${baseContext}
|
|
24396
|
+
|
|
24397
|
+
ROLE: MONITOR \u2014 Watch Experiment Status
|
|
24398
|
+
${workspace.monitor.detachedTask ? `DETACHED TASK: ${workspace.monitor.detachedTask}
|
|
24399
|
+
Complete the detached task, then check experiment status.` : "Watch the experiment status."}
|
|
24400
|
+
|
|
24401
|
+
INSTRUCTIONS:
|
|
24402
|
+
1. Check autoresearch status: autoresearch(action="status")
|
|
24403
|
+
2. Report GPU utilization and any concerning patterns
|
|
24404
|
+
3. If the experiment seems hung, report that
|
|
24405
|
+
|
|
24406
|
+
Call task_complete with JSON: { "status": string, "gpu_usage": string, "concerns": string[] }`, workspace, (event) => onEvent?.({ ...event, content: event.type === "status" ? `[monitor] ${event.content ?? ""}` : event.content }))
|
|
24407
|
+
]);
|
|
24408
|
+
workspace.monitor.status = "idle";
|
|
24409
|
+
const researcherOutput = researcherResult.status === "fulfilled" ? researcherResult.value : "{}";
|
|
24410
|
+
let experimentValBpb = Infinity;
|
|
24411
|
+
let changesMade = hypothesis;
|
|
24412
|
+
try {
|
|
24413
|
+
const parsed = JSON.parse(researcherOutput.match(/\{[\s\S]*\}/)?.[0] ?? "{}");
|
|
24414
|
+
if (typeof parsed.val_bpb === "number")
|
|
24415
|
+
experimentValBpb = parsed.val_bpb;
|
|
24416
|
+
if (typeof parsed.changes_made === "string")
|
|
24417
|
+
changesMade = parsed.changes_made;
|
|
24418
|
+
} catch {
|
|
24419
|
+
}
|
|
24420
|
+
const evaluatorResult = await this.runSwarmAgent("evaluator", `${baseContext}
|
|
24421
|
+
|
|
24422
|
+
ROLE: EVALUATOR \u2014 Assess Experiment Results
|
|
24423
|
+
Evaluate the experiment that just completed:
|
|
24424
|
+
|
|
24425
|
+
HYPOTHESIS: ${hypothesis}
|
|
24426
|
+
RESULT: val_bpb = ${experimentValBpb === Infinity ? "unknown/failed" : experimentValBpb.toFixed(6)}
|
|
24427
|
+
CHANGES: ${changesMade}
|
|
24428
|
+
BEST SO FAR: ${workspace.bestValBpb === Infinity ? "N/A" : workspace.bestValBpb.toFixed(6)}
|
|
24429
|
+
MONITOR REPORT: ${monitorResult.status === "fulfilled" ? monitorResult.value : "unavailable"}
|
|
24430
|
+
|
|
24431
|
+
INSTRUCTIONS:
|
|
24432
|
+
1. Check experiment results using autoresearch(action="results")
|
|
24433
|
+
2. Compare to previous best val_bpb
|
|
24434
|
+
3. If improved: call autoresearch(action="keep", description="...") and write insights to memory
|
|
24435
|
+
4. If worse: call autoresearch(action="discard", description="...") and record failed approach
|
|
24436
|
+
5. Extract architectural insights regardless of outcome
|
|
24437
|
+
|
|
24438
|
+
Use memory_write to save insights to "autoresearch" topic.
|
|
24439
|
+
|
|
24440
|
+
Call task_complete with JSON: { "verdict": "keep"|"discard", "val_bpb": number, "insights": string, "architectural_lesson": string }`, workspace, (event) => onEvent?.({ ...event, content: event.type === "status" ? `[evaluator] ${event.content ?? ""}` : event.content }));
|
|
24441
|
+
let verdict = "discard";
|
|
24442
|
+
let insights = "";
|
|
24443
|
+
try {
|
|
24444
|
+
const parsed = JSON.parse(evaluatorResult.match(/\{[\s\S]*\}/)?.[0] ?? "{}");
|
|
24445
|
+
if (parsed.verdict === "keep")
|
|
24446
|
+
verdict = "keep";
|
|
24447
|
+
if (typeof parsed.val_bpb === "number" && parsed.val_bpb < experimentValBpb) {
|
|
24448
|
+
experimentValBpb = parsed.val_bpb;
|
|
24449
|
+
}
|
|
24450
|
+
if (typeof parsed.insights === "string")
|
|
24451
|
+
insights = parsed.insights;
|
|
24452
|
+
} catch {
|
|
24453
|
+
}
|
|
24454
|
+
if (verdict === "keep" && experimentValBpb < workspace.bestValBpb) {
|
|
24455
|
+
workspace.bestValBpb = experimentValBpb;
|
|
24456
|
+
}
|
|
24457
|
+
workspace.experimentResults.push({
|
|
24458
|
+
hypothesis,
|
|
24459
|
+
valBpb: experimentValBpb,
|
|
24460
|
+
verdict,
|
|
24461
|
+
insights
|
|
24462
|
+
});
|
|
24463
|
+
workspace.roundsCompleted = round + 1;
|
|
24464
|
+
const flowDecision = await this.runSwarmAgent("flow_maintainer", `${baseContext}
|
|
24465
|
+
|
|
24466
|
+
ROLE: FLOW MAINTAINER \u2014 Continue/Stop Decision
|
|
24467
|
+
Round ${round + 1}/${maxRounds} just completed.
|
|
24468
|
+
|
|
24469
|
+
EXPERIMENT HISTORY:
|
|
24470
|
+
${workspace.experimentResults.map((r, i) => `Round ${i + 1}: ${r.hypothesis} \u2192 val_bpb=${r.valBpb === Infinity ? "failed" : r.valBpb.toFixed(6)} (${r.verdict})`).join("\n")}
|
|
24471
|
+
|
|
24472
|
+
REMAINING HYPOTHESES: ${workspace.hypothesisQueue.length}
|
|
24473
|
+
${workspace.hypothesisQueue.map((h, i) => ` ${i + 1}. ${h}`).join("\n") || " (none)"}
|
|
24474
|
+
|
|
24475
|
+
DECISIONS:
|
|
24476
|
+
1. Should we continue to the next round? (consider: are we improving? are hypotheses promising?)
|
|
24477
|
+
2. Should the monitor be given a detached task between rounds? (e.g., "analyze GPU memory patterns")
|
|
24478
|
+
3. Any hypotheses to add or remove from the queue?
|
|
24479
|
+
|
|
24480
|
+
Call task_complete with JSON: { "continue": boolean, "reason": string, "monitor_task": string|null, "add_hypotheses": string[], "remove_indices": number[] }`, workspace, (event) => onEvent?.({ ...event, content: event.type === "status" ? `[flow_maintainer] ${event.content ?? ""}` : event.content }));
|
|
24481
|
+
try {
|
|
24482
|
+
const parsed = JSON.parse(flowDecision.match(/\{[\s\S]*\}/)?.[0] ?? "{}");
|
|
24483
|
+
if (typeof parsed.monitor_task === "string" && parsed.monitor_task) {
|
|
24484
|
+
workspace.monitor.status = "detached";
|
|
24485
|
+
workspace.monitor.detachedTask = parsed.monitor_task;
|
|
24486
|
+
}
|
|
24487
|
+
if (Array.isArray(parsed.add_hypotheses)) {
|
|
24488
|
+
workspace.hypothesisQueue.push(...parsed.add_hypotheses.map(String));
|
|
24489
|
+
}
|
|
24490
|
+
if (Array.isArray(parsed.remove_indices)) {
|
|
24491
|
+
const toRemove = new Set(parsed.remove_indices.map(Number));
|
|
24492
|
+
workspace.hypothesisQueue = workspace.hypothesisQueue.filter((_, i) => !toRemove.has(i));
|
|
24493
|
+
}
|
|
24494
|
+
if (parsed.continue === false) {
|
|
24495
|
+
onEvent?.({
|
|
24496
|
+
type: "status",
|
|
24497
|
+
content: `[flow_maintainer] Stopping early: ${parsed.reason ?? "no reason"}`,
|
|
24498
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
24499
|
+
});
|
|
24500
|
+
break;
|
|
24501
|
+
}
|
|
24502
|
+
} catch {
|
|
24503
|
+
}
|
|
24504
|
+
}
|
|
24505
|
+
renderSwarmPhase(3, "Writing consolidated summary");
|
|
24506
|
+
const summaryResult = await this.runSwarmAgent("flow_maintainer", `${baseContext}
|
|
24507
|
+
|
|
24508
|
+
ROLE: FLOW MAINTAINER \u2014 Final Summary
|
|
24509
|
+
All experiment rounds are complete. Write a consolidated summary.
|
|
24510
|
+
|
|
24511
|
+
EXPERIMENT RESULTS:
|
|
24512
|
+
${workspace.experimentResults.map((r, i) => `Round ${i + 1}: ${r.hypothesis}
|
|
24513
|
+
val_bpb: ${r.valBpb === Infinity ? "failed" : r.valBpb.toFixed(6)}
|
|
24514
|
+
verdict: ${r.verdict}
|
|
24515
|
+
insights: ${r.insights}`).join("\n\n")}
|
|
24516
|
+
|
|
24517
|
+
BEST val_bpb: ${workspace.bestValBpb === Infinity ? "no successful experiments" : workspace.bestValBpb.toFixed(6)}
|
|
24518
|
+
|
|
24519
|
+
INSTRUCTIONS:
|
|
24520
|
+
1. Write a consolidated summary of all experiments to memory using memory_write:
|
|
24521
|
+
- Topic: "autoresearch"
|
|
24522
|
+
- Include: best_config, experiment_log, architectural_insights, failed_approaches, hypothesis_queue
|
|
24523
|
+
2. Summarize the key learnings and next steps
|
|
24524
|
+
|
|
24525
|
+
Call task_complete with a human-readable summary of the autoresearch session.`, workspace, onEvent);
|
|
24526
|
+
const reportPath = join36(this.dreamsDir, `cycle-${cycleNum}-autoresearch-report.md`);
|
|
24527
|
+
const report = `# Autoresearch Swarm Report \u2014 Cycle ${cycleNum}
|
|
24528
|
+
|
|
24529
|
+
**Date**: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
|
|
24530
|
+
**Rounds completed**: ${workspace.roundsCompleted}
|
|
24531
|
+
**Best val_bpb**: ${workspace.bestValBpb === Infinity ? "N/A" : workspace.bestValBpb.toFixed(6)}
|
|
24532
|
+
|
|
24533
|
+
## Experiments
|
|
24534
|
+
|
|
24535
|
+
${workspace.experimentResults.map((r, i) => `### Round ${i + 1}: ${r.hypothesis}
|
|
24536
|
+
- **val_bpb**: ${r.valBpb === Infinity ? "failed" : r.valBpb.toFixed(6)}
|
|
24537
|
+
- **Verdict**: ${r.verdict}
|
|
24538
|
+
- **Insights**: ${r.insights || "none"}`).join("\n\n")}
|
|
24539
|
+
|
|
24540
|
+
## Summary
|
|
24541
|
+
|
|
24542
|
+
${summaryResult}
|
|
24543
|
+
|
|
24544
|
+
---
|
|
24545
|
+
*Generated by open-agents autoresearch swarm*
|
|
24546
|
+
`;
|
|
24547
|
+
try {
|
|
24548
|
+
mkdirSync12(this.dreamsDir, { recursive: true });
|
|
24549
|
+
writeFileSync11(reportPath, report, "utf-8");
|
|
24550
|
+
} catch {
|
|
24551
|
+
}
|
|
24552
|
+
renderSwarmComplete(workspace);
|
|
24553
|
+
return { summary: summaryResult };
|
|
24554
|
+
}
|
|
23983
24555
|
/** Build tools appropriate for the dream mode */
|
|
23984
24556
|
buildDreamTools(toolMode) {
|
|
23985
24557
|
if (toolMode === "full") {
|
|
@@ -24596,7 +25168,8 @@ var init_dmn_engine = __esm({
|
|
|
24596
25168
|
"browser_action \u2014 headless Chrome automation",
|
|
24597
25169
|
"scheduler, reminder, agenda \u2014 temporal agency",
|
|
24598
25170
|
"codebase_map, diagnostic, git_info \u2014 project analysis",
|
|
24599
|
-
"sub_agent \u2014 delegate subtasks to independent agents"
|
|
25171
|
+
"sub_agent \u2014 delegate subtasks to independent agents",
|
|
25172
|
+
"autoresearch \u2014 autonomous GPU ML experiment loop (modify architecture/hyperparams, train 5min, keep/discard)"
|
|
24600
25173
|
];
|
|
24601
25174
|
const prompt = buildDMNGatherPrompt(this.recentTaskSummaries, reminders, attention, memoryTopics, capabilities, this.state.competence, this.state.reflectionBuffer);
|
|
24602
25175
|
const modelTier = getModelTier(this.config.model);
|
|
@@ -25019,7 +25592,7 @@ OUTPUT: Call task_complete with JSON:
|
|
|
25019
25592
|
task: String(p.task ?? ""),
|
|
25020
25593
|
rationale: String(p.rationale ?? ""),
|
|
25021
25594
|
provenance: Array.isArray(p.provenance) ? p.provenance.map(String) : [],
|
|
25022
|
-
category: ["directive", "exploration", "capability", "maintenance", "social"].includes(String(p.category)) ? String(p.category) : "exploration",
|
|
25595
|
+
category: ["directive", "exploration", "capability", "maintenance", "social", "autoresearch"].includes(String(p.category)) ? String(p.category) : "exploration",
|
|
25023
25596
|
confidence: typeof p.confidence === "number" ? p.confidence : 0.5,
|
|
25024
25597
|
challengeResult: p.challengeResult ? String(p.challengeResult) : void 0
|
|
25025
25598
|
}));
|
|
@@ -25070,7 +25643,7 @@ OUTPUT: Call task_complete with JSON:
|
|
|
25070
25643
|
task: String(t.task ?? ""),
|
|
25071
25644
|
rationale: String(t.rationale ?? ""),
|
|
25072
25645
|
provenance: Array.isArray(t.provenance) ? t.provenance.map(String) : [],
|
|
25073
|
-
category: ["directive", "exploration", "capability", "maintenance", "social"].includes(t.category) ? t.category : "exploration",
|
|
25646
|
+
category: ["directive", "exploration", "capability", "maintenance", "social", "autoresearch"].includes(t.category) ? t.category : "exploration",
|
|
25074
25647
|
confidence: typeof t.confidence === "number" ? Math.min(1, Math.max(0, t.confidence)) : 0.5,
|
|
25075
25648
|
challengeResult: t.challengeResult ? String(t.challengeResult) : void 0
|
|
25076
25649
|
};
|
package/package.json
CHANGED