@ryanfw/prompt-orchestration-pipeline 0.3.0 → 0.5.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/package.json +2 -1
- package/src/cli/index.js +16 -28
- package/src/core/orchestrator.js +92 -78
- package/src/ui/dist/assets/index-CxcrauYR.js +22702 -0
- package/src/ui/dist/assets/style-D6K_oQ12.css +62 -0
- package/src/ui/dist/index.html +2 -2
- package/src/ui/dist/assets/index-BDABnI-4.js +0 -33399
- package/src/ui/dist/assets/style-Ks8LY8gB.css +0 -28496
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ryanfw/prompt-orchestration-pipeline",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "A Prompt-orchestration pipeline (POP) is a framework for building, running, and experimenting with complex chains of LLM tasks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/ui/server.js",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"ui": "NODE_ENV=development nodemon src/ui/server.js",
|
|
27
27
|
"ui:dev": "vite",
|
|
28
28
|
"ui:build": "vite build",
|
|
29
|
+
"prepack": "npm run ui:build",
|
|
29
30
|
"ui:prod": "node src/ui/server.js",
|
|
30
31
|
"demo:ui": "NODE_ENV=production PO_ROOT=demo node src/ui/server.js",
|
|
31
32
|
"demo:orchestrator": "PO_ROOT=demo NODE_ENV=production node -e \"import('./src/core/orchestrator.js').then(m => m.startOrchestrator({ dataDir: process.env.PO_ROOT || 'demo' })).catch(err => { console.error(err); process.exit(1) })\"",
|
package/src/cli/index.js
CHANGED
|
@@ -4,9 +4,14 @@ import { submitJobWithValidation } from "../api/index.js";
|
|
|
4
4
|
import { PipelineOrchestrator } from "../api/index.js";
|
|
5
5
|
import fs from "node:fs/promises";
|
|
6
6
|
import path from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
7
8
|
import { spawn } from "node:child_process";
|
|
8
9
|
import { updatePipelineJson } from "./update-pipeline-json.js";
|
|
9
10
|
|
|
11
|
+
// Derive package root for resolving internal paths regardless of host CWD
|
|
12
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
13
|
+
const PKG_ROOT = path.dirname(path.dirname(path.dirname(currentFile)));
|
|
14
|
+
|
|
10
15
|
// Canonical stage names that must match src/core/task-runner.js
|
|
11
16
|
const STAGE_NAMES = [
|
|
12
17
|
"ingestion",
|
|
@@ -140,46 +145,29 @@ program
|
|
|
140
145
|
});
|
|
141
146
|
|
|
142
147
|
try {
|
|
143
|
-
// Step d:
|
|
144
|
-
const distPath = path.join(
|
|
148
|
+
// Step d: Check for prebuilt UI assets
|
|
149
|
+
const distPath = path.join(PKG_ROOT, "src/ui/dist");
|
|
145
150
|
try {
|
|
146
151
|
await fs.access(distPath);
|
|
147
152
|
console.log("UI build found, skipping build step");
|
|
148
153
|
} catch {
|
|
149
|
-
console.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
"node_modules/vite/bin/vite.js"
|
|
154
|
-
);
|
|
155
|
-
const buildChild = spawn("node", [vitePath, "build"], {
|
|
156
|
-
stdio: "inherit",
|
|
157
|
-
env: { ...process.env, NODE_ENV: "development" },
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
buildChild.on("exit", (code) => {
|
|
161
|
-
if (code === 0) {
|
|
162
|
-
console.log("UI build completed");
|
|
163
|
-
resolve();
|
|
164
|
-
} else {
|
|
165
|
-
reject(new Error(`UI build failed with code ${code}`));
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
buildChild.on("error", reject);
|
|
170
|
-
});
|
|
154
|
+
console.error(
|
|
155
|
+
"UI assets missing. This indicates a source checkout. Run 'npm run ui:build' locally or install dev deps."
|
|
156
|
+
);
|
|
157
|
+
process.exit(1);
|
|
171
158
|
}
|
|
172
159
|
|
|
173
160
|
// Step e: Spawn UI server
|
|
174
161
|
console.log("Starting UI server...");
|
|
175
|
-
const uiServerPath = path.
|
|
162
|
+
const uiServerPath = path.join(PKG_ROOT, "src/ui/server.js");
|
|
176
163
|
uiChild = spawn("node", [uiServerPath], {
|
|
177
164
|
stdio: "pipe",
|
|
178
165
|
env: {
|
|
179
166
|
...process.env,
|
|
180
167
|
NODE_ENV: "production",
|
|
181
168
|
PO_ROOT: absoluteRoot,
|
|
182
|
-
|
|
169
|
+
PORT: port,
|
|
170
|
+
PO_UI_PORT: undefined, // Ensure PORT takes precedence
|
|
183
171
|
},
|
|
184
172
|
});
|
|
185
173
|
|
|
@@ -194,8 +182,8 @@ program
|
|
|
194
182
|
|
|
195
183
|
// Step f: Spawn orchestrator
|
|
196
184
|
console.log("Starting orchestrator...");
|
|
197
|
-
const orchestratorPath = path.
|
|
198
|
-
|
|
185
|
+
const orchestratorPath = path.join(
|
|
186
|
+
PKG_ROOT,
|
|
199
187
|
"src/cli/run-orchestrator.js"
|
|
200
188
|
);
|
|
201
189
|
orchestratorChild = spawn("node", [orchestratorPath], {
|
package/src/core/orchestrator.js
CHANGED
|
@@ -220,97 +220,111 @@ export async function startOrchestrator(opts) {
|
|
|
220
220
|
* @param {Object} seed - Seed data containing pipeline information
|
|
221
221
|
*/
|
|
222
222
|
function spawnRunner(jobId, dirs, running, spawn, testMode, seed) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
"core",
|
|
227
|
-
"pipeline-runner.js"
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
const configSnapshot = getConfig();
|
|
231
|
-
const availablePipelines = Object.keys(configSnapshot?.pipelines ?? {});
|
|
232
|
-
const pipelineSlug = seed?.pipeline;
|
|
233
|
-
|
|
234
|
-
console.log("[Orchestrator] spawnRunner invoked", {
|
|
235
|
-
jobId,
|
|
236
|
-
pipelineSlug: pipelineSlug ?? null,
|
|
237
|
-
availablePipelines,
|
|
238
|
-
seedKeys: seed ? Object.keys(seed) : null,
|
|
239
|
-
});
|
|
223
|
+
// Use path relative to this file to avoid process.cwd() issues
|
|
224
|
+
const orchestratorDir = path.dirname(new URL(import.meta.url).pathname);
|
|
225
|
+
const runnerPath = path.join(orchestratorDir, "pipeline-runner.js");
|
|
240
226
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
} else if (!availablePipelines.includes(pipelineSlug)) {
|
|
246
|
-
console.warn(
|
|
247
|
-
"[Orchestrator] Requested pipeline slug missing from registry snapshot",
|
|
248
|
-
{
|
|
249
|
-
jobId,
|
|
250
|
-
pipelineSlug,
|
|
251
|
-
availablePipelines,
|
|
252
|
-
}
|
|
253
|
-
);
|
|
254
|
-
}
|
|
227
|
+
// Set PO_ROOT for the orchestrator process to match what the runner will use
|
|
228
|
+
const originalPoRoot = process.env.PO_ROOT;
|
|
229
|
+
const poRoot = path.resolve(dirs.dataDir, "..");
|
|
230
|
+
process.env.PO_ROOT = poRoot;
|
|
255
231
|
|
|
256
|
-
|
|
257
|
-
|
|
232
|
+
try {
|
|
233
|
+
const configSnapshot = getConfig();
|
|
234
|
+
const availablePipelines = Object.keys(configSnapshot?.pipelines ?? {});
|
|
235
|
+
const pipelineSlug = seed?.pipeline;
|
|
236
|
+
|
|
237
|
+
console.log("[Orchestrator] spawnRunner invoked", {
|
|
258
238
|
jobId,
|
|
259
|
-
|
|
239
|
+
pipelineSlug: pipelineSlug ?? null,
|
|
260
240
|
availablePipelines,
|
|
241
|
+
seedKeys: seed ? Object.keys(seed) : null,
|
|
261
242
|
});
|
|
262
|
-
throw new Error(
|
|
263
|
-
"Pipeline slug is required in seed data. Include a 'pipeline' field in your seed."
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
243
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
244
|
+
if (!availablePipelines.length) {
|
|
245
|
+
console.warn(
|
|
246
|
+
"[Orchestrator] No pipelines registered in config() when spawnRunner invoked"
|
|
247
|
+
);
|
|
248
|
+
} else if (!availablePipelines.includes(pipelineSlug)) {
|
|
249
|
+
console.warn(
|
|
250
|
+
"[Orchestrator] Requested pipeline slug missing from registry snapshot",
|
|
251
|
+
{
|
|
252
|
+
jobId,
|
|
253
|
+
pipelineSlug,
|
|
254
|
+
availablePipelines,
|
|
255
|
+
}
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (!pipelineSlug) {
|
|
260
|
+
console.error("[Orchestrator] Missing pipeline slug in seed", {
|
|
261
|
+
jobId,
|
|
262
|
+
seed,
|
|
263
|
+
availablePipelines,
|
|
264
|
+
});
|
|
265
|
+
throw new Error(
|
|
266
|
+
"Pipeline slug is required in seed data. Include a 'pipeline' field in your seed."
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
let pipelineConfig;
|
|
271
|
+
try {
|
|
272
|
+
pipelineConfig = getPipelineConfig(pipelineSlug);
|
|
273
|
+
} catch (error) {
|
|
274
|
+
console.error("[Orchestrator] Pipeline lookup failed", {
|
|
275
|
+
jobId,
|
|
276
|
+
pipelineSlug,
|
|
277
|
+
availablePipelines,
|
|
278
|
+
});
|
|
279
|
+
throw error;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Use environment variables with explicit slug propagation
|
|
283
|
+
// PO_ROOT should point to the directory containing pipeline-config
|
|
284
|
+
// In our case, it's the parent of pipeline-data directory
|
|
285
|
+
const env = {
|
|
286
|
+
...process.env,
|
|
287
|
+
PO_ROOT: poRoot,
|
|
288
|
+
PO_DATA_DIR: dirs.dataDir,
|
|
289
|
+
PO_PENDING_DIR: dirs.pending,
|
|
290
|
+
PO_CURRENT_DIR: dirs.current,
|
|
291
|
+
PO_COMPLETE_DIR: dirs.complete,
|
|
292
|
+
PO_PIPELINE_SLUG: pipelineSlug,
|
|
293
|
+
// Force mock provider for testing
|
|
294
|
+
PO_DEFAULT_PROVIDER: "mock",
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
// Always call spawn so tests can capture it
|
|
298
|
+
const child = spawn(process.execPath, [runnerPath, jobId], {
|
|
299
|
+
stdio: ["ignore", "inherit", "inherit"],
|
|
300
|
+
env,
|
|
301
|
+
cwd: process.cwd(),
|
|
275
302
|
});
|
|
276
|
-
throw error;
|
|
277
|
-
}
|
|
278
303
|
|
|
279
|
-
|
|
280
|
-
const env = {
|
|
281
|
-
...process.env,
|
|
282
|
-
PO_DATA_DIR: dirs.dataDir,
|
|
283
|
-
PO_PENDING_DIR: dirs.pending,
|
|
284
|
-
PO_CURRENT_DIR: dirs.current,
|
|
285
|
-
PO_COMPLETE_DIR: dirs.complete,
|
|
286
|
-
PO_PIPELINE_SLUG: pipelineSlug,
|
|
287
|
-
// Force mock provider for testing
|
|
288
|
-
PO_DEFAULT_PROVIDER: "mock",
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
// Always call spawn so tests can capture it
|
|
292
|
-
const child = spawn(process.execPath, [runnerPath, jobId], {
|
|
293
|
-
stdio: ["ignore", "inherit", "inherit"],
|
|
294
|
-
env,
|
|
295
|
-
cwd: process.cwd(),
|
|
296
|
-
});
|
|
304
|
+
running.set(jobId, child);
|
|
297
305
|
|
|
298
|
-
|
|
306
|
+
child.on("exit", () => {
|
|
307
|
+
running.delete(jobId);
|
|
308
|
+
});
|
|
309
|
+
child.on("error", () => {
|
|
310
|
+
running.delete(jobId);
|
|
311
|
+
});
|
|
299
312
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
running.delete(jobId);
|
|
305
|
-
});
|
|
313
|
+
// In test mode: return immediately; in real mode you might await readiness
|
|
314
|
+
if (testMode) {
|
|
315
|
+
return child;
|
|
316
|
+
}
|
|
306
317
|
|
|
307
|
-
|
|
308
|
-
if (testMode) {
|
|
318
|
+
// Non-test: we can consider "started" immediately for simplicity
|
|
309
319
|
return child;
|
|
320
|
+
} finally {
|
|
321
|
+
// Restore original PO_ROOT
|
|
322
|
+
if (originalPoRoot) {
|
|
323
|
+
process.env.PO_ROOT = originalPoRoot;
|
|
324
|
+
} else {
|
|
325
|
+
delete process.env.PO_ROOT;
|
|
326
|
+
}
|
|
310
327
|
}
|
|
311
|
-
|
|
312
|
-
// Non-test: we can consider "started" immediately for simplicity
|
|
313
|
-
return child;
|
|
314
328
|
}
|
|
315
329
|
|
|
316
330
|
export default { startOrchestrator };
|