@ryanfw/prompt-orchestration-pipeline 1.3.0 → 1.3.2
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/README.md +1 -0
- package/docs/pop-task-guide.md +45 -0
- package/package.json +3 -3
- package/src/core/__tests__/agent-step.test.ts +402 -35
- package/src/core/__tests__/task-runner.test.ts +104 -0
- package/src/core/agent-step.ts +295 -41
- package/src/core/agent-types.ts +61 -0
- package/src/core/file-io.ts +8 -74
- package/src/core/orchestrator.ts +2 -1
- package/src/core/pipeline-definition.ts +1 -1
- package/src/core/pipeline-runner.ts +54 -3
- package/src/core/status-writer.ts +44 -26
- package/src/core/task-runner.ts +44 -1
- package/src/core/validation.ts +1 -1
- package/src/harness/__tests__/discovery.test.ts +235 -0
- package/src/harness/discovery.ts +109 -0
- package/src/harness/index.ts +22 -0
- package/src/harness/mcp-io-server.ts +1 -1
- package/src/ui/client/hooks/useJobListWithUpdates.ts +16 -1
- package/src/ui/dist/assets/{index-D7hzshSS.js → index--RH3sAt3.js} +129 -1
- package/src/ui/dist/assets/index--RH3sAt3.js.map +1 -0
- package/src/ui/dist/assets/style-CSSKuMOe.css +2 -0
- package/src/ui/dist/index.html +2 -2
- package/src/ui/embedded-assets.js +6 -6
- package/src/ui/pages/Code.tsx +135 -0
- package/src/ui/server/__tests__/gate-endpoints.test.ts +90 -0
- package/src/ui/server/__tests__/job-control-endpoints.test.ts +188 -0
- package/src/ui/server/__tests__/path-containment.test.ts +54 -0
- package/src/ui/server/__tests__/status-corruption.test.ts +55 -0
- package/src/ui/server/config-bridge.ts +1 -0
- package/src/ui/server/endpoints/__tests__/upload-endpoints.test.ts +77 -0
- package/src/ui/server/endpoints/gate-endpoints.ts +17 -1
- package/src/ui/server/endpoints/job-control-endpoints.ts +36 -2
- package/src/ui/server/endpoints/upload-endpoints.ts +13 -3
- package/src/ui/server/utils/http-utils.ts +6 -1
- package/src/ui/server/utils/path-containment.ts +18 -0
- package/src/ui/server/utils/status-corruption.ts +27 -0
- package/src/harness/__tests__/descriptors.test.ts +0 -378
- package/src/harness/__tests__/executor.test.ts +0 -193
- package/src/harness/__tests__/resolve.test.ts +0 -200
- package/src/harness/__tests__/types.test.ts +0 -297
- package/src/harness/descriptors/claude.ts +0 -132
- package/src/harness/descriptors/codex.ts +0 -126
- package/src/harness/descriptors/index.ts +0 -10
- package/src/harness/descriptors/opencode.ts +0 -147
- package/src/harness/executor.ts +0 -128
- package/src/harness/resolve.ts +0 -176
- package/src/harness/types.ts +0 -100
- package/src/ui/dist/assets/index-D7hzshSS.js.map +0 -1
- package/src/ui/dist/assets/style-BUFg3Sth.css +0 -2
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export {
|
|
2
|
+
run,
|
|
3
|
+
getHarnessStatus,
|
|
4
|
+
discoverHarnesses,
|
|
5
|
+
listModels,
|
|
6
|
+
HarnessRunError,
|
|
7
|
+
} from "local-llm-cli-adapter";
|
|
8
|
+
|
|
9
|
+
export type {
|
|
10
|
+
HarnessName,
|
|
11
|
+
HarnessEvent,
|
|
12
|
+
Usage,
|
|
13
|
+
RunFailureReason,
|
|
14
|
+
RunResult,
|
|
15
|
+
RunOptions,
|
|
16
|
+
HarnessRun,
|
|
17
|
+
HarnessStatus,
|
|
18
|
+
ModelOption,
|
|
19
|
+
ModelPayload,
|
|
20
|
+
McpServerConfig,
|
|
21
|
+
PermissionMode,
|
|
22
|
+
} from "local-llm-cli-adapter";
|
|
@@ -4,7 +4,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
4
4
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import type { TaskFileIO } from "../core/file-io.ts";
|
|
7
|
-
import type { McpServerConnection } from "
|
|
7
|
+
import type { McpServerConnection } from "../core/agent-types.ts";
|
|
8
8
|
|
|
9
9
|
export interface McpIoServerHandle {
|
|
10
10
|
connection: McpServerConnection;
|
|
@@ -33,8 +33,23 @@ function sortNormalizedJobs(jobs: NormalizedJobSummary[]): NormalizedJobSummary[
|
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
function completedCountFromTasks(job: NormalizedJobSummary): number {
|
|
37
|
+
return Object.values(job.tasks).filter((task) => task.state === "done" || task.state === "skipped").length;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function comparableJob(job: NormalizedJobSummary): Record<string, unknown> {
|
|
41
|
+
const comparable: Record<string, unknown> = { ...job };
|
|
42
|
+
for (const [key, value] of Object.entries(comparable)) {
|
|
43
|
+
if (value === undefined) delete comparable[key];
|
|
44
|
+
}
|
|
45
|
+
if (comparable["completedCount"] === completedCountFromTasks(job)) {
|
|
46
|
+
delete comparable["completedCount"];
|
|
47
|
+
}
|
|
48
|
+
return comparable;
|
|
49
|
+
}
|
|
50
|
+
|
|
36
51
|
function jobsEqual(left: NormalizedJobSummary[], right: NormalizedJobSummary[]): boolean {
|
|
37
|
-
return JSON.stringify(left) === JSON.stringify(right);
|
|
52
|
+
return JSON.stringify(left.map(comparableJob)) === JSON.stringify(right.map(comparableJob));
|
|
38
53
|
}
|
|
39
54
|
|
|
40
55
|
function mergeJob(current: NormalizedJobSummary, incoming: NormalizedJobSummary): NormalizedJobSummary {
|
|
@@ -20094,6 +20094,15 @@ const createLucideIcon = (iconName, iconNode) => {
|
|
|
20094
20094
|
Component.displayName = toPascalCase(iconName);
|
|
20095
20095
|
return Component;
|
|
20096
20096
|
};
|
|
20097
|
+
const __iconNode$h = [
|
|
20098
|
+
["path", { d: "M12 8V4H8", key: "hb8ula" }],
|
|
20099
|
+
["rect", { width: "16", height: "12", x: "4", y: "8", rx: "2", key: "enze0r" }],
|
|
20100
|
+
["path", { d: "M2 14h2", key: "vft8re" }],
|
|
20101
|
+
["path", { d: "M20 14h2", key: "4cs60a" }],
|
|
20102
|
+
["path", { d: "M15 13v2", key: "1xurst" }],
|
|
20103
|
+
["path", { d: "M9 13v2", key: "rq6x2g" }]
|
|
20104
|
+
];
|
|
20105
|
+
const Bot = createLucideIcon("bot", __iconNode$h);
|
|
20097
20106
|
const __iconNode$g = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
|
|
20098
20107
|
const Check = createLucideIcon("check", __iconNode$g);
|
|
20099
20108
|
const __iconNode$f = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
|
|
@@ -21096,6 +21105,7 @@ const SECTIONS = [
|
|
|
21096
21105
|
{ id: "run-control", label: "Run Control", icon: GitBranch },
|
|
21097
21106
|
{ id: "io-api", label: "IO API", icon: Database },
|
|
21098
21107
|
{ id: "llm-api", label: "LLM API", icon: Cpu },
|
|
21108
|
+
{ id: "agent-api", label: "Agent API", icon: Bot },
|
|
21099
21109
|
{ id: "validation", label: "Validation", icon: Shield }
|
|
21100
21110
|
];
|
|
21101
21111
|
const SAMPLE_PIPELINE_JSON = {
|
|
@@ -21226,6 +21236,26 @@ const VALIDATION_EXAMPLE_CODE = `export const validateStructure = async ({
|
|
|
21226
21236
|
}
|
|
21227
21237
|
return { output: {}, flags };
|
|
21228
21238
|
};`;
|
|
21239
|
+
const AGENT_OPTIONS = [
|
|
21240
|
+
{ name: "harness", required: true, type: '"claude" | "codex" | "opencode"', description: "Which CLI agent to run." },
|
|
21241
|
+
{ name: "prompt", required: true, type: "string", description: "The instruction handed to the agent. Build it from seed or upstream stage data." },
|
|
21242
|
+
{ name: "model", required: false, type: "string", description: "Model id passed through to the CLI verbatim." },
|
|
21243
|
+
{ name: "io", required: false, type: "boolean", description: "Bridge POP file I/O into the agent (read_artifact / write_artifact tools). Default true." },
|
|
21244
|
+
{ name: "timeoutMs", required: false, type: "number", description: "Overall wall-clock cap in milliseconds." },
|
|
21245
|
+
{ name: "captureDiff", required: false, type: "boolean", description: "Capture a git diff of the working tree as an agent.patch artifact." }
|
|
21246
|
+
];
|
|
21247
|
+
const AGENT_EXAMPLE_CODE = `export const inference = async ({ runAgent, io, data, flags }) => {
|
|
21248
|
+
// Build the prompt programmatically from upstream data
|
|
21249
|
+
const prompt = \`Summarize: \${data.ingestion.topic}.\` +
|
|
21250
|
+
" Save the summary as a POP artifact named summary.md via write_artifact.";
|
|
21251
|
+
|
|
21252
|
+
const result = await runAgent({ harness: "claude", prompt });
|
|
21253
|
+
if (!result.ok) throw new Error(result.error);
|
|
21254
|
+
|
|
21255
|
+
// The agent wrote summary.md through POP's bridged file I/O
|
|
21256
|
+
const summary = await io.readArtifact("summary.md");
|
|
21257
|
+
return { output: { summary }, flags };
|
|
21258
|
+
};`;
|
|
21229
21259
|
function CollapsibleSection({
|
|
21230
21260
|
id,
|
|
21231
21261
|
title,
|
|
@@ -21693,6 +21723,91 @@ function Code() {
|
|
|
21693
21723
|
]
|
|
21694
21724
|
}
|
|
21695
21725
|
) }),
|
|
21726
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { id: "agent-api", ref: sectionRef("agent-api"), className: "scroll-mt-24", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
21727
|
+
CollapsibleSection,
|
|
21728
|
+
{
|
|
21729
|
+
id: "agent-api",
|
|
21730
|
+
title: "Agent API",
|
|
21731
|
+
icon: Bot,
|
|
21732
|
+
isOpen: openSections["agent-api"],
|
|
21733
|
+
onToggle: () => toggle("agent-api"),
|
|
21734
|
+
children: [
|
|
21735
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-base text-gray-600 mb-6", children: [
|
|
21736
|
+
"Run a CLI coding agent (claude, codex, or opencode) from inside a task stage with",
|
|
21737
|
+
" ",
|
|
21738
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-sm font-mono", children: "runAgent" }),
|
|
21739
|
+
". Unlike a single",
|
|
21740
|
+
" ",
|
|
21741
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-sm font-mono", children: "llm" }),
|
|
21742
|
+
" call, the agent uses tools over multiple turns and can read and write the task's artifacts."
|
|
21743
|
+
] }),
|
|
21744
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [
|
|
21745
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
21746
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium mb-3 block", children: "Options" }),
|
|
21747
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border border-gray-200 rounded-md overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("table", { className: "w-full text-sm", children: [
|
|
21748
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("thead", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { children: [
|
|
21749
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "bg-gray-50 px-4 py-3 text-left font-medium", children: "Option" }),
|
|
21750
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "bg-gray-50 px-4 py-3 text-left font-medium", children: "Type" }),
|
|
21751
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "bg-gray-50 px-4 py-3 text-left font-medium", children: "Required" }),
|
|
21752
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "bg-gray-50 px-4 py-3 text-left font-medium", children: "Description" })
|
|
21753
|
+
] }) }),
|
|
21754
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("tbody", { children: AGENT_OPTIONS.map((field) => /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "border-t border-gray-100", children: [
|
|
21755
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-sm font-mono", children: field.name }) }),
|
|
21756
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-xs font-mono text-gray-600", children: field.type }) }),
|
|
21757
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-4 py-3", children: field.required ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-600 font-medium", children: "Yes" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-400", children: "No" }) }),
|
|
21758
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-4 py-3 text-gray-600", children: field.description })
|
|
21759
|
+
] }, field.name)) })
|
|
21760
|
+
] }) })
|
|
21761
|
+
] }),
|
|
21762
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
21763
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium mb-2 block", children: "Returns" }),
|
|
21764
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-gray-50 rounded-md p-3 border border-gray-200", children: /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-sm font-mono", children: `Promise<{ ok, finalMessage, artifactsWritten, usage?, costUsd?, sessionId?, error? }>` }) })
|
|
21765
|
+
] }),
|
|
21766
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-[#f5f3ff] border border-[#ede9fe] rounded-md p-4", children: [
|
|
21767
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
|
|
21768
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Bot, { className: "h-4 w-4 text-[#6d28d9]" }),
|
|
21769
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium text-gray-900", children: "runAgent vs llm vs agent entries" }),
|
|
21770
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { intent: "green", children: "NEW" })
|
|
21771
|
+
] }),
|
|
21772
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("ul", { className: "space-y-1 text-sm text-gray-700", children: [
|
|
21773
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "flex items-start gap-2", children: [
|
|
21774
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[#6d28d9] mt-0.5", children: "•" }),
|
|
21775
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
21776
|
+
"Use ",
|
|
21777
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono text-xs", children: "llm.<provider>.chat()" }),
|
|
21778
|
+
" for a single request/response model call."
|
|
21779
|
+
] })
|
|
21780
|
+
] }),
|
|
21781
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "flex items-start gap-2", children: [
|
|
21782
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[#6d28d9] mt-0.5", children: "•" }),
|
|
21783
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
21784
|
+
"Use ",
|
|
21785
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono text-xs", children: "runAgent()" }),
|
|
21786
|
+
" for a tool-using CLI agent that reads and writes files over multiple turns."
|
|
21787
|
+
] })
|
|
21788
|
+
] }),
|
|
21789
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "flex items-start gap-2", children: [
|
|
21790
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[#6d28d9] mt-0.5", children: "•" }),
|
|
21791
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
21792
|
+
"Prefer ",
|
|
21793
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono text-xs", children: "runAgent()" }),
|
|
21794
|
+
" over a static",
|
|
21795
|
+
" ",
|
|
21796
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono text-xs", children: "agent:" }),
|
|
21797
|
+
" pipeline entry when the prompt is built from seed or stage data."
|
|
21798
|
+
] })
|
|
21799
|
+
] })
|
|
21800
|
+
] })
|
|
21801
|
+
] }),
|
|
21802
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
21803
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium mb-2 block", children: "Usage Example" }),
|
|
21804
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CopyableCodeBlock, { maxHeight: "260px", children: AGENT_EXAMPLE_CODE })
|
|
21805
|
+
] }),
|
|
21806
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-gray-500", children: "Requires the selected harness CLI to be installed and authenticated on the host." })
|
|
21807
|
+
] })
|
|
21808
|
+
]
|
|
21809
|
+
}
|
|
21810
|
+
) }),
|
|
21696
21811
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { id: "validation", ref: sectionRef("validation"), className: "scroll-mt-24", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
21697
21812
|
CollapsibleSection,
|
|
21698
21813
|
{
|
|
@@ -78316,8 +78431,21 @@ function sortNormalizedJobs(jobs) {
|
|
|
78316
78431
|
return left.jobId.localeCompare(right.jobId);
|
|
78317
78432
|
});
|
|
78318
78433
|
}
|
|
78434
|
+
function completedCountFromTasks(job) {
|
|
78435
|
+
return Object.values(job.tasks).filter((task) => task.state === "done" || task.state === "skipped").length;
|
|
78436
|
+
}
|
|
78437
|
+
function comparableJob(job) {
|
|
78438
|
+
const comparable = { ...job };
|
|
78439
|
+
for (const [key, value] of Object.entries(comparable)) {
|
|
78440
|
+
if (value === void 0) delete comparable[key];
|
|
78441
|
+
}
|
|
78442
|
+
if (comparable["completedCount"] === completedCountFromTasks(job)) {
|
|
78443
|
+
delete comparable["completedCount"];
|
|
78444
|
+
}
|
|
78445
|
+
return comparable;
|
|
78446
|
+
}
|
|
78319
78447
|
function jobsEqual(left, right) {
|
|
78320
|
-
return JSON.stringify(left) === JSON.stringify(right);
|
|
78448
|
+
return JSON.stringify(left.map(comparableJob)) === JSON.stringify(right.map(comparableJob));
|
|
78321
78449
|
}
|
|
78322
78450
|
function mergeJob(current, incoming) {
|
|
78323
78451
|
return {
|