Skip to content

Commit c402419

Browse files
demo: agent_swarm.omc — parallel agent swarm for recursive self-improvement
Orchestrator decomposes a goal into N sub-tasks, runs all workers in parallel (batch_llm_call), evaluates + repairs low-scoring outputs (score < 6/10), then synthesizes into a final coherent result. Loops for multiple rounds. Uses: json_extract, str_format, batch_llm_call, par_map, llm_call, arr_fill, arr_sort, arr_join, eval_omc Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 7439f1f commit c402419

1 file changed

Lines changed: 208 additions & 0 deletions

File tree

examples/demos/agent_swarm.omc

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
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

Comments
 (0)