|
| 1 | +# agent_swarm.omc — Parallel agent swarm for recursive self-improvement |
| 2 | +# |
| 3 | +# Architecture: |
| 4 | +# - Orchestrator decomposes a goal into N sub-tasks |
| 5 | +# - Swarm of worker agents processes tasks in parallel (batch_llm_call) |
| 6 | +# - Results are aggregated and synthesized |
| 7 | +# - Output is evaluated, lowest-scoring results are revised |
| 8 | +# - Loop repeats for multiple rounds |
| 9 | +# |
| 10 | +# Requires: ANTHROPIC_API_KEY or LLM_PROVIDER=anthropic |
| 11 | + |
| 12 | +print("=== OMC Agent Swarm: Recursive Self-Improvement ===") |
| 13 | +print("") |
| 14 | + |
| 15 | +# ── Configuration ───────────────────────────────────────────────────────────── |
| 16 | + |
| 17 | +h MODEL = "claude-3-5-haiku-20241022" |
| 18 | +h SWARM_SIZE = 4 |
| 19 | +h ROUNDS = 2 |
| 20 | + |
| 21 | +# ── Orchestrator: decompose goal into tasks ─────────────────────────────────── |
| 22 | + |
| 23 | +fn decompose_goal(goal, n, model) { |
| 24 | + h prompt = str_format( |
| 25 | + "Break this goal into exactly {n} parallel independent sub-tasks. Each task should be completable in one LLM call.\n\nGoal: {goal}\n\nRespond with JSON: {{\"tasks\": [\"task1\", \"task2\", ...]}}", |
| 26 | + {goal: goal, n: to_str(n)} |
| 27 | + ) |
| 28 | + h raw = llm_call(prompt, model) |
| 29 | + h parsed = json_extract(raw) |
| 30 | + if parsed == null { |
| 31 | + return arr_fill(goal, n) |
| 32 | + } |
| 33 | + h tasks = parsed["tasks"] |
| 34 | + if tasks == null { return arr_fill(goal, n) } |
| 35 | + return tasks |
| 36 | +} |
| 37 | + |
| 38 | +# ── Worker: execute a single task ───────────────────────────────────────────── |
| 39 | + |
| 40 | +fn worker_execute(task, context, model) { |
| 41 | + h prompt = if str_len(context) > 0 { |
| 42 | + str_format( |
| 43 | + "Context:\n{ctx}\n\nYour task: {task}\n\nProvide a detailed, concrete response.", |
| 44 | + {ctx: context, task: task} |
| 45 | + ) |
| 46 | + } else { |
| 47 | + str_concat("Your task: ", task, "\n\nProvide a detailed, concrete response.") |
| 48 | + } |
| 49 | + return prompt |
| 50 | +} |
| 51 | + |
| 52 | +# ── Evaluator: score outputs ─────────────────────────────────────────────────── |
| 53 | + |
| 54 | +fn evaluate_output(task, output, model) { |
| 55 | + h prompt = str_format( |
| 56 | + "Rate this output for the task (0-10). Be strict.\n\nTask: {task}\n\nOutput: {out}\n\nRespond with JSON: {{\"score\": N, \"issues\": [\"...\"]}}", |
| 57 | + {task: task, out: str_slice(output, 0, 300)} |
| 58 | + ) |
| 59 | + h raw = llm_call(prompt, model) |
| 60 | + h parsed = json_extract(raw) |
| 61 | + if parsed == null { return {score: 5, issues: []} } |
| 62 | + return parsed |
| 63 | +} |
| 64 | + |
| 65 | +# ── Synthesizer: combine all outputs ───────────────────────────────────────── |
| 66 | + |
| 67 | +fn synthesize_outputs(goal, tasks, outputs, model) { |
| 68 | + h parts = [] |
| 69 | + h i = 0 |
| 70 | + while i < arr_len(tasks) { |
| 71 | + arr_push(parts, str_format("TASK {n}: {t}\nOUTPUT: {o}", { |
| 72 | + n: to_str(i + 1), |
| 73 | + t: tasks[i], |
| 74 | + o: outputs[i] |
| 75 | + })) |
| 76 | + i = i + 1 |
| 77 | + } |
| 78 | + h combined = arr_join(parts, "\n\n---\n\n") |
| 79 | + h prompt = str_format( |
| 80 | + "Goal: {goal}\n\nYou have {n} completed sub-tasks:\n\n{combined}\n\nSynthesize all outputs into a coherent final result:", |
| 81 | + {goal: goal, n: to_str(arr_len(tasks)), combined: combined} |
| 82 | + ) |
| 83 | + return llm_call(prompt, model) |
| 84 | +} |
| 85 | + |
| 86 | +# ── Repair: fix low-scoring outputs ────────────────────────────────────────── |
| 87 | + |
| 88 | +fn repair_output(task, output, issues, model) { |
| 89 | + h issues_text = arr_join(issues, "\n- ") |
| 90 | + h prompt = str_format( |
| 91 | + "Fix this output addressing the issues.\n\nTask: {task}\n\nCurrent output: {out}\n\nIssues:\n- {issues}\n\nFixed output:", |
| 92 | + {task: task, out: output, issues: issues_text} |
| 93 | + ) |
| 94 | + return llm_call(prompt, model) |
| 95 | +} |
| 96 | + |
| 97 | +# ── Main Swarm Loop ─────────────────────────────────────────────────────────── |
| 98 | + |
| 99 | +fn run_swarm(goal, swarm_size, rounds, model) { |
| 100 | + print(str_concat("Goal: ", goal)) |
| 101 | + print(str_concat("Swarm size: ", to_str(swarm_size), " workers, ", to_str(rounds), " rounds")) |
| 102 | + print("") |
| 103 | + |
| 104 | + # Decompose |
| 105 | + print("Phase 1: Decomposing goal into sub-tasks...") |
| 106 | + h tasks = decompose_goal(goal, swarm_size, model) |
| 107 | + print(str_concat(" Created ", to_str(arr_len(tasks)), " tasks")) |
| 108 | + h i = 0 |
| 109 | + while i < arr_len(tasks) { |
| 110 | + print(str_concat(" [", to_str(i + 1), "] ", str_slice(tasks[i], 0, 70))) |
| 111 | + i = i + 1 |
| 112 | + } |
| 113 | + print("") |
| 114 | + |
| 115 | + # Round loop |
| 116 | + h outputs = arr_fill("", swarm_size) |
| 117 | + h round = 0 |
| 118 | + while round < rounds { |
| 119 | + print(str_concat("Phase 2.", to_str(round + 1), ": Parallel execution (swarm)...")) |
| 120 | + |
| 121 | + # Build prompts for all workers |
| 122 | + h context = if round == 0 { "" } else { |
| 123 | + str_concat("Previous round context: ", str_slice(arr_join(outputs, " | "), 0, 200)) |
| 124 | + } |
| 125 | + h prompts = par_map(tasks, fn(task) { |
| 126 | + return worker_execute(task, context, model) |
| 127 | + }) |
| 128 | + |
| 129 | + # Run all workers in parallel |
| 130 | + h new_outputs = batch_llm_call(prompts, model) |
| 131 | + outputs = new_outputs |
| 132 | + |
| 133 | + print(str_concat(" Got ", to_str(arr_len(outputs)), " outputs")) |
| 134 | + |
| 135 | + if round < rounds - 1 { |
| 136 | + # Evaluate and repair low-scoring outputs |
| 137 | + print("Phase 3: Evaluating and repairing...") |
| 138 | + h eval_prompts = [] |
| 139 | + h j = 0 |
| 140 | + while j < arr_len(tasks) { |
| 141 | + arr_push(eval_prompts, str_format( |
| 142 | + "Rate (0-10) and list issues. Task: {t}\nOutput: {o}\nJSON: {{\"score\":N,\"issues\":[]}}", |
| 143 | + {t: tasks[j], o: str_slice(outputs[j], 0, 200)} |
| 144 | + )) |
| 145 | + j = j + 1 |
| 146 | + } |
| 147 | + h eval_raws = batch_llm_call(eval_prompts, model) |
| 148 | + h evals = par_map(eval_raws, fn(raw) { |
| 149 | + h j = json_extract(raw) |
| 150 | + if j != null { return j } |
| 151 | + return {score: 7, issues: []} |
| 152 | + }) |
| 153 | + |
| 154 | + h repair_prompts = [] |
| 155 | + h k = 0 |
| 156 | + while k < arr_len(tasks) { |
| 157 | + h ev = evals[k] |
| 158 | + h score = to_float(to_str(ev["score"])) |
| 159 | + if score < 6.0 { |
| 160 | + h issues = ev["issues"] |
| 161 | + h issues_text = if issues != null { arr_join(issues, "; ") } else { "Needs improvement" } |
| 162 | + arr_push(repair_prompts, { |
| 163 | + idx: k, |
| 164 | + prompt: str_format( |
| 165 | + "Fix this output.\nTask: {t}\nOutput: {o}\nIssues: {i}\nFixed:", |
| 166 | + {t: tasks[k], o: str_slice(outputs[k], 0, 200), i: issues_text} |
| 167 | + ) |
| 168 | + }) |
| 169 | + print(str_concat(" Repairing task ", to_str(k + 1), " (score=", to_str(score), ")")) |
| 170 | + } |
| 171 | + k = k + 1 |
| 172 | + } |
| 173 | + |
| 174 | + if arr_len(repair_prompts) > 0 { |
| 175 | + h repair_ps = par_map(repair_prompts, fn(r) { return r["prompt"] }) |
| 176 | + h repaired = batch_llm_call(repair_ps, model) |
| 177 | + h m = 0 |
| 178 | + while m < arr_len(repair_prompts) { |
| 179 | + h idx = repair_prompts[m]["idx"] |
| 180 | + outputs[idx] = repaired[m] |
| 181 | + m = m + 1 |
| 182 | + } |
| 183 | + } |
| 184 | + } |
| 185 | + round = round + 1 |
| 186 | + } |
| 187 | + |
| 188 | + # Synthesize |
| 189 | + print("") |
| 190 | + print("Phase 4: Synthesizing final result...") |
| 191 | + h final = synthesize_outputs(goal, tasks, outputs, model) |
| 192 | + print("Done!") |
| 193 | + return { |
| 194 | + final: final, |
| 195 | + tasks: tasks, |
| 196 | + outputs: outputs |
| 197 | + } |
| 198 | +} |
| 199 | + |
| 200 | +# ── Run the swarm ───────────────────────────────────────────────────────────── |
| 201 | + |
| 202 | +h goal = "Design a complete OMC program that implements a self-improving code optimizer" |
| 203 | + |
| 204 | +h result = run_swarm(goal, SWARM_SIZE, ROUNDS, MODEL) |
| 205 | + |
| 206 | +print("") |
| 207 | +print("=== FINAL SYNTHESIZED RESULT ===") |
| 208 | +print(result["final"]) |
0 commit comments