@ryanfw/prompt-orchestration-pipeline 0.17.1 → 0.17.3

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.
@@ -253,16 +253,67 @@ Each stage receives:
253
253
  preProcessing, // Output from preProcessing
254
254
  promptTemplating, // Output from promptTemplating
255
255
  // ... other stage outputs
256
- },
257
- output, // Previous non-validation stage output
258
- }
259
- ```
260
-
261
- ---
262
-
263
- ## Summary
264
-
265
- 1. Export only valid stage names: `ingestion`, `preProcessing`, `promptTemplating`, `inference`, `parsing`, `validateStructure`, `validateQuality`, `critique`, `refine`, `finalValidation`, `integration`
266
- 2. Return `{ output, flags }` from every stage
267
- 3. Custom helper functions are valid JavaScript but will not be called by the pipeline—only use them if called from within a valid stage
268
- 4. Most simple tasks need only: `ingestion` `promptTemplating` → `inference`
256
+ },
257
+ output, // Previous non-validation stage output
258
+ }
259
+ ```
260
+
261
+ ---
262
+
263
+ ## Detailed Stage Reference
264
+
265
+ This reference describes the intent and responsibility of each standard phase. All phases execute sequentially.
266
+
267
+ ### 1. Ingestion
268
+ **Purpose**: Load and extract raw input data from the seed.
269
+ **Responsibility**: Read input parameters, extract required fields, and pass data forward.
270
+
271
+ ### 2. PreProcessing
272
+ **Purpose**: Normalize and prepare input data.
273
+ **Responsibility**: Clean input formats, deduplicate arrays, set defaults, and sanitize data.
274
+
275
+ ### 3. PromptTemplating
276
+ **Purpose**: Build structured prompts for the LLM.
277
+ **Responsibility**: Create system and user prompts, including output format specifications.
278
+
279
+ ### 4. Inference
280
+ **Purpose**: Execute the LLM call.
281
+ **Responsibility**: Call the LLM API, handle raw responses, and write initial output artifacts.
282
+
283
+ ### 5. Parsing
284
+ **Purpose**: Transform raw output into typed structure.
285
+ **Responsibility**: specific parsing logic if not handled during inference (e.g. complex regex extraction).
286
+
287
+ ### 6. ValidateStructure
288
+ **Purpose**: Validate response against JSON schema.
289
+ **Responsibility**: programmatic validation using Ajv or similar. Sets `needsRefinement: true` if invalid.
290
+
291
+ ### 7. ValidateQuality
292
+ **Purpose**: LLM-based content quality assessment.
293
+ **Responsibility**: Check for factual consistency, completeness, and specific requirements. Sets `needsRefinement: true` if issues found.
294
+
295
+ ### 8. Critique
296
+ **Purpose**: Generate improvement instructions.
297
+ **Responsibility**: If validation failed, analyze errors and generate actionable feedback.
298
+
299
+ ### 9. Refine
300
+ **Purpose**: Re-run the core task with improvements.
301
+ **Responsibility**: If `needsRefinement` is true, call LLM again with original prompt + critique.
302
+
303
+ ### 10. FinalValidation
304
+ **Purpose**: Safety gate for refined output.
305
+ **Responsibility**: Re-validate structure to ensure refinement didn't break the JSON schema.
306
+
307
+ ### 11. Integration
308
+ **Purpose**: Persist and organize final results.
309
+ **Responsibility**: Save final artifacts to databases, files, or trigger downstream workflows.
310
+
311
+ ---
312
+
313
+ ## Summary
314
+
315
+ 1. Export only valid stage names: `ingestion`, `preProcessing`, `promptTemplating`, `inference`, `parsing`, `validateStructure`, `validateQuality`, `critique`, `refine`, `finalValidation`, `integration`
316
+ 2. Return `{ output, flags }` from every stage
317
+ 3. Custom helper functions are valid JavaScript but will not be called by the pipeline—only use them if called from within a valid stage
318
+ 4. Most simple tasks need only: `ingestion` → `promptTemplating` → `inference`
319
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryanfw/prompt-orchestration-pipeline",
3
- "version": "0.17.1",
3
+ "version": "0.17.3",
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",
@@ -588,6 +588,9 @@ function DAGGrid({
588
588
  if (options?.singleTask) {
589
589
  restartOptions.singleTask = options.singleTask;
590
590
  }
591
+ if (options?.continueAfter) {
592
+ restartOptions.continueAfter = options.continueAfter;
593
+ }
591
594
 
592
595
  await restartJob(jobId, restartOptions);
593
596
 
@@ -81,6 +81,15 @@ export function RestartJobModal({
81
81
  tabIndex={-1}
82
82
  onKeyDown={handleKeyDown}
83
83
  >
84
+ {/* Close button */}
85
+ <button
86
+ onClick={onClose}
87
+ disabled={isSubmitting}
88
+ className="absolute top-4 right-4 text-gray-500 hover:text-gray-700 text-xl font-light"
89
+ aria-label="Close"
90
+ >
91
+ &times;
92
+ </button>
84
93
  <div className="p-6">
85
94
  {/* Header */}
86
95
  <Heading
@@ -107,10 +116,6 @@ export function RestartJobModal({
107
116
  <Text as="p" className="text-sm text-gray-600 mb-3">
108
117
  <strong>Triggered from task:</strong> {taskId}
109
118
  </Text>
110
- <Text as="p" className="text-sm text-blue-600 mb-3">
111
- <strong>Just this task:</strong> Only the selected task will
112
- be reset and re-run. Other tasks remain unchanged.
113
- </Text>
114
119
  </>
115
120
  )}
116
121
 
@@ -120,31 +125,30 @@ export function RestartJobModal({
120
125
  </Box>
121
126
 
122
127
  {/* Actions */}
123
- <Flex gap="3" justify="end">
124
- <Button
125
- variant="outline"
126
- onClick={onClose}
127
- disabled={isSubmitting}
128
- className="min-w-[80px]"
129
- >
130
- Cancel
131
- </Button>
132
-
128
+ <Flex direction="column" gap="2" justify="end" align="end">
133
129
  {taskId ? (
134
130
  <>
135
131
  <Button
136
132
  variant="outline"
137
133
  onClick={() => onConfirm({ singleTask: false })}
138
134
  disabled={isSubmitting}
139
- className="min-w-[120px]"
135
+ className="w-full sm:w-auto"
140
136
  >
141
137
  {isSubmitting ? "Restarting..." : "Restart entire pipeline"}
142
138
  </Button>
139
+ <Button
140
+ variant="outline"
141
+ onClick={() => onConfirm({ singleTask: true, continueAfter: true })}
142
+ disabled={isSubmitting}
143
+ className="w-full sm:w-auto"
144
+ >
145
+ {isSubmitting ? "Running..." : "Re-run task and continue pipeline"}
146
+ </Button>
143
147
  <Button
144
148
  variant="default"
145
149
  onClick={() => onConfirm({ singleTask: true })}
146
150
  disabled={isSubmitting}
147
- className="min-w-[120px]"
151
+ className="w-full sm:w-auto"
148
152
  >
149
153
  {isSubmitting ? "Running..." : "Re-run this task"}
150
154
  </Button>
@@ -154,7 +158,7 @@ export function RestartJobModal({
154
158
  variant="destructive"
155
159
  onClick={() => onConfirm({ singleTask: false })}
156
160
  disabled={isSubmitting}
157
- className="min-w-[80px]"
161
+ className="w-full sm:w-auto"
158
162
  >
159
163
  {isSubmitting ? "Restarting..." : "Restart"}
160
164
  </Button>
@@ -7,10 +7,49 @@ import {
7
7
  ProviderJsonParseError,
8
8
  createProviderError,
9
9
  } from "./base.js";
10
+ import { deepseekChat } from "./deepseek.js";
10
11
  import { createLogger } from "../core/logger.js";
11
12
 
12
13
  const logger = createLogger("Moonshot");
13
14
 
15
+ function isContentFilterError(error) {
16
+ return (
17
+ error.status === 400 &&
18
+ /high risk|rejected/i.test(error.message)
19
+ );
20
+ }
21
+
22
+ async function fallbackToDeepSeek({
23
+ messages,
24
+ temperature,
25
+ maxTokens,
26
+ responseFormat,
27
+ topP,
28
+ frequencyPenalty,
29
+ presencePenalty,
30
+ stop,
31
+ stream,
32
+ thinking,
33
+ }) {
34
+ const fallbackModel = thinking === "enabled" ? "deepseek-reasoner" : "deepseek-chat";
35
+ logger.warn("Moonshot content filter triggered, falling back to DeepSeek", {
36
+ fallbackModel,
37
+ thinking,
38
+ });
39
+ return deepseekChat({
40
+ messages,
41
+ model: fallbackModel,
42
+ temperature,
43
+ maxTokens,
44
+ responseFormat,
45
+ topP,
46
+ frequencyPenalty,
47
+ presencePenalty,
48
+ stop,
49
+ stream,
50
+ });
51
+ }
52
+
14
53
  export async function moonshotChat({
15
54
  messages,
16
55
  model = "moonshot-v1-128k",
@@ -22,6 +61,7 @@ export async function moonshotChat({
22
61
  presencePenalty,
23
62
  stop,
24
63
  stream = false,
64
+ thinking = "enabled",
25
65
  maxRetries = 3,
26
66
  }) {
27
67
  const isJsonMode =
@@ -162,6 +202,22 @@ export async function moonshotChat({
162
202
  errorStatus: error.status,
163
203
  });
164
204
 
205
+ // Check for content filter error and attempt DeepSeek fallback
206
+ if (isContentFilterError(error) && process.env.DEEPSEEK_API_KEY) {
207
+ return fallbackToDeepSeek({
208
+ messages,
209
+ temperature,
210
+ maxTokens,
211
+ responseFormat,
212
+ topP,
213
+ frequencyPenalty,
214
+ presencePenalty,
215
+ stop,
216
+ stream,
217
+ thinking,
218
+ });
219
+ }
220
+
165
221
  if (error.status === 401) throw error;
166
222
 
167
223
  if (isRetryableError(error) && attempt < maxRetries) {
@@ -9,6 +9,7 @@
9
9
  * @param {Object} opts - Options object
10
10
  * @param {string} [opts.fromTask] - Task ID to restart from (inclusive)
11
11
  * @param {boolean} [opts.singleTask] - Whether to run only the target task and then stop
12
+ * @param {boolean} [opts.continueAfter] - Whether to continue pipeline after the single task completes
12
13
  * @param {Object} [opts.options] - Additional options for the restart
13
14
  * @param {boolean} [opts.options.clearTokenUsage=true] - Whether to clear token usage
14
15
  * @returns {Promise<Object>} Parsed JSON response from the server
@@ -25,11 +26,13 @@ export async function restartJob(jobId, opts = {}) {
25
26
  fromTask: opts.fromTask,
26
27
  options,
27
28
  ...(opts.singleTask !== undefined && { singleTask: opts.singleTask }),
29
+ ...(opts.continueAfter !== undefined && { continueAfter: opts.continueAfter }),
28
30
  }
29
31
  : {
30
32
  mode: "clean-slate",
31
33
  options,
32
34
  ...(opts.singleTask !== undefined && { singleTask: opts.singleTask }),
35
+ ...(opts.continueAfter !== undefined && { continueAfter: opts.continueAfter }),
33
36
  };
34
37
 
35
38
  try {
@@ -24794,7 +24794,7 @@ function RestartJobModal({
24794
24794
  "aria-hidden": "true"
24795
24795
  }
24796
24796
  ),
24797
- /* @__PURE__ */ jsxRuntimeExports.jsx(
24797
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
24798
24798
  "div",
24799
24799
  {
24800
24800
  ref: modalRef,
@@ -24806,61 +24806,65 @@ function RestartJobModal({
24806
24806
  style: { minWidth: "320px", maxWidth: "560px" },
24807
24807
  tabIndex: -1,
24808
24808
  onKeyDown: handleKeyDown,
24809
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6", children: [
24809
+ children: [
24810
24810
  /* @__PURE__ */ jsxRuntimeExports.jsx(
24811
- r$a,
24811
+ "button",
24812
24812
  {
24813
- id: "restart-modal-title",
24814
- as: "h2",
24815
- size: "5",
24816
- className: "mb-4 text-gray-900",
24817
- children: taskId ? `Restart from ${taskId}` : "Restart job (reset progress)"
24813
+ onClick: onClose,
24814
+ disabled: isSubmitting,
24815
+ className: "absolute top-4 right-4 text-gray-500 hover:text-gray-700 text-xl font-light",
24816
+ "aria-label": "Close",
24817
+ children: "×"
24818
24818
  }
24819
24819
  ),
24820
- /* @__PURE__ */ jsxRuntimeExports.jsxs(p$9, { id: "restart-modal-description", className: "mb-6", children: [
24821
- /* @__PURE__ */ jsxRuntimeExports.jsx(p$d, { as: "p", className: "text-gray-700 mb-4", children: taskId ? `This will restart the job from the "${taskId}" task. Tasks before ${taskId} will remain completed, while ${taskId} and all subsequent tasks will be reset to pending. Files and artifacts are preserved. A new background run will start automatically. This cannot be undone.` : "This will clear the job's progress and active stage and reset all tasks to pending. Files and artifacts are preserved. A new background run will start automatically. This cannot be undone." }),
24822
- taskId && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
24823
- /* @__PURE__ */ jsxRuntimeExports.jsxs(p$d, { as: "p", className: "text-sm text-gray-600 mb-3", children: [
24824
- /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Triggered from task:" }),
24825
- " ",
24826
- taskId
24827
- ] }),
24828
- /* @__PURE__ */ jsxRuntimeExports.jsxs(p$d, { as: "p", className: "text-sm text-blue-600 mb-3", children: [
24829
- /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Just this task:" }),
24830
- " Only the selected task will be reset and re-run. Other tasks remain unchanged."
24831
- ] })
24832
- ] }),
24833
- /* @__PURE__ */ jsxRuntimeExports.jsx(p$d, { as: "p", className: "text-sm text-gray-500 italic", children: "Note: Job must be in current lifecycle and not running." })
24834
- ] }),
24835
- /* @__PURE__ */ jsxRuntimeExports.jsxs(p$6, { gap: "3", justify: "end", children: [
24820
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6", children: [
24836
24821
  /* @__PURE__ */ jsxRuntimeExports.jsx(
24837
- Button,
24822
+ r$a,
24838
24823
  {
24839
- variant: "outline",
24840
- onClick: onClose,
24841
- disabled: isSubmitting,
24842
- className: "min-w-[80px]",
24843
- children: "Cancel"
24824
+ id: "restart-modal-title",
24825
+ as: "h2",
24826
+ size: "5",
24827
+ className: "mb-4 text-gray-900",
24828
+ children: taskId ? `Restart from ${taskId}` : "Restart job (reset progress)"
24844
24829
  }
24845
24830
  ),
24846
- taskId ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
24831
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(p$9, { id: "restart-modal-description", className: "mb-6", children: [
24832
+ /* @__PURE__ */ jsxRuntimeExports.jsx(p$d, { as: "p", className: "text-gray-700 mb-4", children: taskId ? `This will restart the job from the "${taskId}" task. Tasks before ${taskId} will remain completed, while ${taskId} and all subsequent tasks will be reset to pending. Files and artifacts are preserved. A new background run will start automatically. This cannot be undone.` : "This will clear the job's progress and active stage and reset all tasks to pending. Files and artifacts are preserved. A new background run will start automatically. This cannot be undone." }),
24833
+ taskId && /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(p$d, { as: "p", className: "text-sm text-gray-600 mb-3", children: [
24834
+ /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Triggered from task:" }),
24835
+ " ",
24836
+ taskId
24837
+ ] }) }),
24838
+ /* @__PURE__ */ jsxRuntimeExports.jsx(p$d, { as: "p", className: "text-sm text-gray-500 italic", children: "Note: Job must be in current lifecycle and not running." })
24839
+ ] }),
24840
+ /* @__PURE__ */ jsxRuntimeExports.jsx(p$6, { direction: "column", gap: "2", justify: "end", align: "end", children: taskId ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
24847
24841
  /* @__PURE__ */ jsxRuntimeExports.jsx(
24848
24842
  Button,
24849
24843
  {
24850
24844
  variant: "outline",
24851
24845
  onClick: () => onConfirm({ singleTask: false }),
24852
24846
  disabled: isSubmitting,
24853
- className: "min-w-[120px]",
24847
+ className: "w-full sm:w-auto",
24854
24848
  children: isSubmitting ? "Restarting..." : "Restart entire pipeline"
24855
24849
  }
24856
24850
  ),
24851
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
24852
+ Button,
24853
+ {
24854
+ variant: "outline",
24855
+ onClick: () => onConfirm({ singleTask: true, continueAfter: true }),
24856
+ disabled: isSubmitting,
24857
+ className: "w-full sm:w-auto",
24858
+ children: isSubmitting ? "Running..." : "Re-run task and continue pipeline"
24859
+ }
24860
+ ),
24857
24861
  /* @__PURE__ */ jsxRuntimeExports.jsx(
24858
24862
  Button,
24859
24863
  {
24860
24864
  variant: "default",
24861
24865
  onClick: () => onConfirm({ singleTask: true }),
24862
24866
  disabled: isSubmitting,
24863
- className: "min-w-[120px]",
24867
+ className: "w-full sm:w-auto",
24864
24868
  children: isSubmitting ? "Running..." : "Re-run this task"
24865
24869
  }
24866
24870
  )
@@ -24870,12 +24874,12 @@ function RestartJobModal({
24870
24874
  variant: "destructive",
24871
24875
  onClick: () => onConfirm({ singleTask: false }),
24872
24876
  disabled: isSubmitting,
24873
- className: "min-w-[80px]",
24877
+ className: "w-full sm:w-auto",
24874
24878
  children: isSubmitting ? "Restarting..." : "Restart"
24875
24879
  }
24876
- )
24880
+ ) })
24877
24881
  ] })
24878
- ] })
24882
+ ]
24879
24883
  }
24880
24884
  )
24881
24885
  ]
@@ -24890,11 +24894,13 @@ async function restartJob(jobId, opts = {}) {
24890
24894
  const requestBody = opts.fromTask ? {
24891
24895
  fromTask: opts.fromTask,
24892
24896
  options,
24893
- ...opts.singleTask !== void 0 && { singleTask: opts.singleTask }
24897
+ ...opts.singleTask !== void 0 && { singleTask: opts.singleTask },
24898
+ ...opts.continueAfter !== void 0 && { continueAfter: opts.continueAfter }
24894
24899
  } : {
24895
24900
  mode: "clean-slate",
24896
24901
  options,
24897
- ...opts.singleTask !== void 0 && { singleTask: opts.singleTask }
24902
+ ...opts.singleTask !== void 0 && { singleTask: opts.singleTask },
24903
+ ...opts.continueAfter !== void 0 && { continueAfter: opts.continueAfter }
24898
24904
  };
24899
24905
  try {
24900
24906
  const response = await fetch(
@@ -25641,6 +25647,9 @@ function DAGGrid({
25641
25647
  if (options?.singleTask) {
25642
25648
  restartOptions.singleTask = options.singleTask;
25643
25649
  }
25650
+ if (options?.continueAfter) {
25651
+ restartOptions.continueAfter = options.continueAfter;
25652
+ }
25644
25653
  await restartJob(jobId, restartOptions);
25645
25654
  const successMessage = options?.singleTask ? `Re-running task ${restartTaskId} in isolation. The job will remain in current after completion.` : restartTaskId ? `Restart requested from ${restartTaskId}. The job will start from that task in the background.` : "Restart requested. The job will reset to pending and start in the background.";
25646
25655
  setAlertMessage(successMessage);