MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / Orchestrator

Class Orchestrator

src/orchestration/engine.ts:79–237  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

77{"tasks":[{"id":"t1","kind":"schema","title":"...","instruction":"...","targetFiles":["..."],"contextFiles":[],"dependsOn":[],"visualReview":false}]}`;
78
79export class Orchestrator implements OrchestrationEngine {
80 private graphCache?: ImportGraph;
81
82 constructor(private opts: EngineOptions) {}
83
84 /** Build the file-level import graph for the whole project once. */
85 private async projectGraph(): Promise<ImportGraph> {
86 if (this.graphCache) return this.graphCache;
87 const files = await walkProjectSource(this.opts.cwd, 3000);
88 this.graphCache = await buildImportGraph(
89 this.opts.cwd,
90 files.map(f => ({ rel: f.rel, content: f.content })),
91 );
92 return this.graphCache;
93 }
94
95 /** ORCHESTRATOR: produce the task DAG. */
96 async decompose(goal: string, signal?: AbortSignal): Promise<TaskGraph> {
97 const raw = this.opts.planner
98 ? await this.opts.planner(goal, signal)
99 : await this.planViaModel(goal, signal);
100
101 const nodes = new Map<TaskId, TaskNode>();
102 for (const t of raw.tasks) {
103 nodes.set(t.id, {
104 id: t.id,
105 kind: t.kind,
106 title: t.title,
107 instruction: t.instruction,
108 targetFiles: t.targetFiles ?? [],
109 contextFiles: t.contextFiles ?? [],
110 contextSymbols: t.contextSymbols,
111 dependsOn: t.dependsOn ?? [],
112 role: defaultRoleForKind(t.kind),
113 visualReview: t.visualReview ?? false,
114 status: 'pending',
115 attempts: 0,
116 });
117 }
118
119 const graph: TaskGraph = { nodes, goal, acyclic: false };
120 const order = topoSort(graph);
121 if (!order) {
122 throw new Error('Planner produced a cyclic task graph; cannot schedule. Re-plan with acyclic dependencies.');
123 }
124 graph.acyclic = true;
125 logger.info('Decomposed goal into DAG', { tasks: nodes.size, order });
126 return graph;
127 }
128
129 /** Ask the planning model for the DAG as JSON. */
130 private async planViaModel(goal: string, signal?: AbortSignal): Promise<RawPlan> {
131 const runner = getSubAgentRunner();
132 if (!runner) throw new Error('No sub-agent runner registered; orchestration requires the agent runtime.');
133
134 const prompt = `${PLANNER_SYSTEM}\n\n# Goal\n${goal}\n\nReturn the JSON plan now.`;
135 const res = await runner(prompt, {
136 maxIterations: 1,

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected