refactor(coding-agent): moved swarm extension into workspace package
This commit is contained in:
+4
-4
@@ -9,7 +9,7 @@ Use it for anything: research pipelines, code generation, data processing, conte
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
cd packages/coding-agent/extensions/swarm
|
||||
cd packages/omp-extension-swarm
|
||||
bun install
|
||||
```
|
||||
|
||||
@@ -19,10 +19,10 @@ bun install
|
||||
|
||||
```bash
|
||||
# Foreground — runs until complete, no timeout:
|
||||
bun packages/coding-agent/extensions/swarm/run-pipeline.ts path/to/swarm.yaml
|
||||
bun packages/omp-extension-swarm/run-pipeline.ts path/to/swarm.yaml
|
||||
|
||||
# Background — survives terminal close:
|
||||
nohup bun packages/coding-agent/extensions/swarm/run-pipeline.ts path/to/swarm.yaml \
|
||||
nohup bun packages/omp-extension-swarm/run-pipeline.ts path/to/swarm.yaml \
|
||||
> pipeline.log 2>&1 & disown
|
||||
```
|
||||
|
||||
@@ -34,7 +34,7 @@ Register the extension in your config (`~/.omp/config.json` or `.omp/config.json
|
||||
|
||||
```json
|
||||
{
|
||||
"extensions": ["packages/coding-agent/extensions/swarm"]
|
||||
"extensions": ["packages/omp-extension-swarm"]
|
||||
}
|
||||
```
|
||||
|
||||
+10
-14
@@ -8,26 +8,25 @@
|
||||
* Usage: Add this extension's directory to your extensions config,
|
||||
* then use /swarm in any oh-my-pi session.
|
||||
*/
|
||||
import * as path from "node:path";
|
||||
|
||||
import * as fs from "node:fs/promises";
|
||||
import * as path from "node:path";
|
||||
import type { ExtensionAPI, ExtensionCommandContext } from "@oh-my-pi/pi-coding-agent";
|
||||
import { parseSwarmYaml, validateSwarmDefinition, type SwarmDefinition } from "./swarm/schema";
|
||||
import { buildDependencyGraph, detectCycles, buildExecutionWaves } from "./swarm/dag";
|
||||
import { StateTracker } from "./swarm/state";
|
||||
import { buildDependencyGraph, buildExecutionWaves, detectCycles } from "./swarm/dag";
|
||||
import { PipelineController } from "./swarm/pipeline";
|
||||
import { renderSwarmProgress } from "./swarm/render";
|
||||
import { parseSwarmYaml, type SwarmDefinition, validateSwarmDefinition } from "./swarm/schema";
|
||||
import { StateTracker } from "./swarm/state";
|
||||
|
||||
export default function swarmExtension(pi: ExtensionAPI): void {
|
||||
pi.setLabel("Swarm Orchestrator");
|
||||
|
||||
pi.registerCommand("swarm", {
|
||||
description: "Run a multi-agent swarm pipeline from YAML",
|
||||
getArgumentCompletions: (prefix) => {
|
||||
getArgumentCompletions: prefix => {
|
||||
const subcommands = ["run", "status", "help"];
|
||||
if (!prefix) return subcommands.map((s) => ({ label: s, value: s }));
|
||||
return subcommands
|
||||
.filter((s) => s.startsWith(prefix))
|
||||
.map((s) => ({ label: s, value: s }));
|
||||
if (!prefix) return subcommands.map(s => ({ label: s, value: s }));
|
||||
return subcommands.filter(s => s.startsWith(prefix)).map(s => ({ label: s, value: s }));
|
||||
},
|
||||
handler: async (args: string, ctx: ExtensionCommandContext) => {
|
||||
const parts = args.trim().split(/\s+/);
|
||||
@@ -47,7 +46,6 @@ export default function swarmExtension(pi: ExtensionAPI): void {
|
||||
await handleStatus(parts[1], ctx);
|
||||
return;
|
||||
}
|
||||
case "help":
|
||||
default:
|
||||
ctx.ui.notify(
|
||||
[
|
||||
@@ -93,7 +91,7 @@ async function handleRun(yamlPath: string, ctx: ExtensionCommandContext, pi: Ext
|
||||
// 3. Validate
|
||||
const validationErrors = validateSwarmDefinition(def);
|
||||
if (validationErrors.length > 0) {
|
||||
ctx.ui.notify(`Validation errors:\n${validationErrors.map((e) => ` - ${e}`).join("\n")}`, "error");
|
||||
ctx.ui.notify(`Validation errors:\n${validationErrors.map(e => ` - ${e}`).join("\n")}`, "error");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -249,9 +247,7 @@ function buildSummaryMessage(
|
||||
lines.push("");
|
||||
for (const [name, agent] of Object.entries(stateTracker.state.agents)) {
|
||||
const duration =
|
||||
agent.startedAt && agent.completedAt
|
||||
? formatDuration(agent.completedAt - agent.startedAt)
|
||||
: "n/a";
|
||||
agent.startedAt && agent.completedAt ? formatDuration(agent.completedAt - agent.startedAt) : "n/a";
|
||||
lines.push(`- **${name}**: ${agent.status} (${duration})${agent.error ? ` — ${agent.error}` : ""}`);
|
||||
}
|
||||
|
||||
+7
-6
@@ -3,16 +3,17 @@
|
||||
*
|
||||
* Usage: bun run-pipeline.ts <path-to-yaml>
|
||||
*/
|
||||
import * as path from "node:path";
|
||||
|
||||
import * as fs from "node:fs/promises";
|
||||
import { parseSwarmYaml, validateSwarmDefinition } from "./swarm/schema";
|
||||
import { buildDependencyGraph, detectCycles, buildExecutionWaves } from "./swarm/dag";
|
||||
import { StateTracker } from "./swarm/state";
|
||||
import { PipelineController } from "./swarm/pipeline";
|
||||
import { renderSwarmProgress } from "./swarm/render";
|
||||
import * as path from "node:path";
|
||||
import { discoverAuthStorage } from "@oh-my-pi/pi-coding-agent";
|
||||
import { ModelRegistry } from "@oh-my-pi/pi-coding-agent/config/model-registry";
|
||||
import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import { buildDependencyGraph, buildExecutionWaves, detectCycles } from "./swarm/dag";
|
||||
import { PipelineController } from "./swarm/pipeline";
|
||||
import { renderSwarmProgress } from "./swarm/render";
|
||||
import { parseSwarmYaml, validateSwarmDefinition } from "./swarm/schema";
|
||||
import { StateTracker } from "./swarm/state";
|
||||
|
||||
const yamlPath = process.argv[2];
|
||||
if (!yamlPath) {
|
||||
+7
@@ -55,6 +55,7 @@ export interface SwarmDefinition {
|
||||
// ============================================================================
|
||||
|
||||
const VALID_MODES = new Set<string>(["pipeline", "parallel", "sequential"]);
|
||||
const VALID_SWARM_NAME = /^[a-zA-Z0-9._-]+$/;
|
||||
|
||||
export function parseSwarmYaml(content: string): SwarmDefinition {
|
||||
const raw = YAML.parse(content) as { swarm?: RawSwarmConfig } | null;
|
||||
@@ -66,6 +67,9 @@ export function parseSwarmYaml(content: string): SwarmDefinition {
|
||||
if (!swarm.name || typeof swarm.name !== "string") {
|
||||
throw new Error("swarm.name is required and must be a string");
|
||||
}
|
||||
if (!VALID_SWARM_NAME.test(swarm.name)) {
|
||||
throw new Error("swarm.name may only contain letters, numbers, dot, underscore, and dash");
|
||||
}
|
||||
if (!swarm.workspace || typeof swarm.workspace !== "string") {
|
||||
throw new Error("swarm.workspace is required and must be a string");
|
||||
}
|
||||
@@ -141,6 +145,9 @@ export function validateSwarmDefinition(def: SwarmDefinition): string[] {
|
||||
if (def.targetCount < 1) {
|
||||
errors.push("target_count must be at least 1");
|
||||
}
|
||||
if (def.mode !== "pipeline" && def.targetCount !== 1) {
|
||||
errors.push("target_count is only supported in pipeline mode");
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
+3
-3
@@ -8,9 +8,9 @@
|
||||
"skipLibCheck": true,
|
||||
"types": ["bun-types"],
|
||||
"paths": {
|
||||
"@oh-my-pi/pi-coding-agent": ["../../src/index.ts"],
|
||||
"@oh-my-pi/pi-coding-agent/*": ["../../src/*.ts"]
|
||||
"@oh-my-pi/pi-coding-agent": ["../coding-agent/src/index.ts"],
|
||||
"@oh-my-pi/pi-coding-agent/*": ["../coding-agent/src/*.ts"]
|
||||
}
|
||||
},
|
||||
"include": ["extension.ts", "swarm/**/*.ts"]
|
||||
"include": ["extension.ts", "run-pipeline.ts", "swarm/**/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user