@ryanfw/prompt-orchestration-pipeline 0.17.2 → 0.17.4
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 +1 -1
- package/src/components/DAGGrid.jsx +3 -0
- package/src/providers/moonshot.js +59 -120
- package/src/ui/dist/assets/{index-jIuZSALW.js → index-BidlfsSr.js} +3 -0
- package/src/ui/dist/assets/{index-jIuZSALW.js.map → index-BidlfsSr.js.map} +1 -1
- package/src/ui/dist/index.html +1 -1
- package/src/ui/endpoints/job-control-endpoints.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ryanfw/prompt-orchestration-pipeline",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.4",
|
|
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
|
|
|
@@ -13,25 +13,17 @@ import { createLogger } from "../core/logger.js";
|
|
|
13
13
|
const logger = createLogger("Moonshot");
|
|
14
14
|
|
|
15
15
|
function isContentFilterError(error) {
|
|
16
|
-
return (
|
|
17
|
-
error.status === 400 &&
|
|
18
|
-
/high risk|rejected/i.test(error.message)
|
|
19
|
-
);
|
|
16
|
+
return error.status === 400 && /high risk|rejected/i.test(error.message);
|
|
20
17
|
}
|
|
21
18
|
|
|
22
19
|
async function fallbackToDeepSeek({
|
|
23
20
|
messages,
|
|
24
|
-
temperature,
|
|
25
21
|
maxTokens,
|
|
26
|
-
responseFormat,
|
|
27
|
-
topP,
|
|
28
|
-
frequencyPenalty,
|
|
29
|
-
presencePenalty,
|
|
30
22
|
stop,
|
|
31
|
-
stream,
|
|
32
23
|
thinking,
|
|
33
24
|
}) {
|
|
34
|
-
const fallbackModel =
|
|
25
|
+
const fallbackModel =
|
|
26
|
+
thinking === "enabled" ? "deepseek-reasoner" : "deepseek-chat";
|
|
35
27
|
logger.warn("Moonshot content filter triggered, falling back to DeepSeek", {
|
|
36
28
|
fallbackModel,
|
|
37
29
|
thinking,
|
|
@@ -39,38 +31,36 @@ async function fallbackToDeepSeek({
|
|
|
39
31
|
return deepseekChat({
|
|
40
32
|
messages,
|
|
41
33
|
model: fallbackModel,
|
|
42
|
-
temperature,
|
|
43
34
|
maxTokens,
|
|
44
|
-
responseFormat,
|
|
45
|
-
topP,
|
|
46
|
-
frequencyPenalty,
|
|
47
|
-
presencePenalty,
|
|
35
|
+
responseFormat: "json_object",
|
|
48
36
|
stop,
|
|
49
|
-
stream,
|
|
37
|
+
stream: false,
|
|
50
38
|
});
|
|
51
39
|
}
|
|
52
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Moonshot chat completion for kimi-k2.5 model with JSON mode.
|
|
43
|
+
*
|
|
44
|
+
* Note: kimi-k2.5 does not allow modifying temperature, top_p,
|
|
45
|
+
* presence_penalty, frequency_penalty, or n parameters.
|
|
46
|
+
*
|
|
47
|
+
* @param {Object} options
|
|
48
|
+
* @param {Array} options.messages - Chat messages
|
|
49
|
+
* @param {string} options.model - Model ID (default: kimi-k2.5)
|
|
50
|
+
* @param {number} options.maxTokens - Max tokens to generate
|
|
51
|
+
* @param {string|Array} options.stop - Stop sequences
|
|
52
|
+
* @param {string} options.thinking - "enabled" or "disabled"
|
|
53
|
+
* @param {number} options.maxRetries - Number of retries on failure
|
|
54
|
+
*/
|
|
53
55
|
export async function moonshotChat({
|
|
54
56
|
messages,
|
|
55
|
-
model = "
|
|
56
|
-
|
|
57
|
-
maxTokens,
|
|
58
|
-
responseFormat = "json_object",
|
|
59
|
-
topP,
|
|
60
|
-
frequencyPenalty,
|
|
61
|
-
presencePenalty,
|
|
57
|
+
model = "kimi-k2.5",
|
|
58
|
+
maxTokens = 10000,
|
|
62
59
|
stop,
|
|
63
|
-
stream = false,
|
|
64
60
|
thinking = "enabled",
|
|
65
61
|
maxRetries = 3,
|
|
66
62
|
}) {
|
|
67
|
-
|
|
68
|
-
responseFormat?.type === "json_object" ||
|
|
69
|
-
responseFormat?.type === "json_schema" ||
|
|
70
|
-
responseFormat === "json" ||
|
|
71
|
-
responseFormat === "json_object";
|
|
72
|
-
|
|
73
|
-
logger.log("moonshotChat called", { model, stream, maxRetries, isJsonMode });
|
|
63
|
+
logger.log("moonshotChat called", { model, thinking, maxRetries });
|
|
74
64
|
|
|
75
65
|
if (!process.env.MOONSHOT_API_KEY) {
|
|
76
66
|
throw new Error("Moonshot API key not configured");
|
|
@@ -93,30 +83,32 @@ export async function moonshotChat({
|
|
|
93
83
|
|
|
94
84
|
try {
|
|
95
85
|
logger.log("Sending request to Moonshot API", { attempt, model });
|
|
96
|
-
// Thinking models only accept temperature=1
|
|
97
|
-
//const isThinkingModel = model.includes("thinking");
|
|
98
|
-
//const effectiveTemperature = isThinkingModel ? 1 : temperature;
|
|
99
86
|
|
|
87
|
+
// Build request body for kimi-k2.5
|
|
88
|
+
// Note: temperature, top_p, presence_penalty, frequency_penalty cannot be modified for kimi-k2.5
|
|
100
89
|
const requestBody = {
|
|
101
90
|
model,
|
|
102
91
|
messages: [
|
|
103
92
|
{ role: "system", content: systemMsg },
|
|
104
93
|
{ role: "user", content: userMsg },
|
|
105
94
|
],
|
|
106
|
-
temperature: 1,
|
|
107
95
|
max_tokens: maxTokens,
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
stop,
|
|
112
|
-
stream,
|
|
96
|
+
response_format: { type: "json_object" },
|
|
97
|
+
thinking: { type: thinking },
|
|
98
|
+
stream: false,
|
|
113
99
|
};
|
|
114
100
|
|
|
115
|
-
|
|
116
|
-
|
|
101
|
+
// Only add stop if provided
|
|
102
|
+
if (stop) {
|
|
103
|
+
requestBody.stop = stop;
|
|
117
104
|
}
|
|
118
105
|
|
|
119
|
-
logger.log("
|
|
106
|
+
logger.log("Request body", {
|
|
107
|
+
model: requestBody.model,
|
|
108
|
+
thinking: requestBody.thinking,
|
|
109
|
+
max_tokens: requestBody.max_tokens,
|
|
110
|
+
});
|
|
111
|
+
|
|
120
112
|
const response = await fetch(
|
|
121
113
|
"https://api.moonshot.ai/v1/chat/completions",
|
|
122
114
|
{
|
|
@@ -128,6 +120,7 @@ export async function moonshotChat({
|
|
|
128
120
|
body: JSON.stringify(requestBody),
|
|
129
121
|
},
|
|
130
122
|
);
|
|
123
|
+
|
|
131
124
|
logger.log("Fetch returned", {
|
|
132
125
|
status: response.status,
|
|
133
126
|
ok: response.ok,
|
|
@@ -138,7 +131,6 @@ export async function moonshotChat({
|
|
|
138
131
|
.json()
|
|
139
132
|
.catch(() => ({ error: response.statusText }));
|
|
140
133
|
|
|
141
|
-
// Provide more helpful error message for authentication failures
|
|
142
134
|
if (response.status === 401) {
|
|
143
135
|
const enhancedError = createProviderError(
|
|
144
136
|
response.status,
|
|
@@ -155,42 +147,33 @@ export async function moonshotChat({
|
|
|
155
147
|
);
|
|
156
148
|
}
|
|
157
149
|
|
|
158
|
-
//
|
|
159
|
-
if (stream) {
|
|
160
|
-
logger.log("Handling streaming response");
|
|
161
|
-
return createStreamGenerator(response.body);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Step 7: Handle non-streaming response parsing
|
|
165
|
-
logger.log("Parsing JSON response...");
|
|
150
|
+
// Parse response
|
|
166
151
|
const data = await response.json();
|
|
167
|
-
logger.log("
|
|
152
|
+
logger.log("Response parsed", {
|
|
168
153
|
hasChoices: !!data.choices,
|
|
169
154
|
choicesCount: data.choices?.length,
|
|
170
155
|
});
|
|
171
|
-
const rawContent = data.choices[0].message.content;
|
|
172
156
|
|
|
157
|
+
const rawContent = data.choices[0].message.content;
|
|
173
158
|
const content = stripMarkdownFences(rawContent);
|
|
174
159
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
raw: data,
|
|
189
|
-
};
|
|
160
|
+
// Always parse as JSON (we always use json_object response format)
|
|
161
|
+
const parsed = tryParseJSON(content);
|
|
162
|
+
if (!parsed) {
|
|
163
|
+
logger.warn("JSON parse failed", {
|
|
164
|
+
rawContentPreview: rawContent?.substring(0, 500),
|
|
165
|
+
strippedContentPreview: content?.substring(0, 500),
|
|
166
|
+
});
|
|
167
|
+
throw new ProviderJsonParseError(
|
|
168
|
+
"Moonshot",
|
|
169
|
+
model,
|
|
170
|
+
content?.substring(0, 200),
|
|
171
|
+
"Failed to parse JSON response from Moonshot API",
|
|
172
|
+
);
|
|
190
173
|
}
|
|
191
174
|
|
|
192
175
|
return {
|
|
193
|
-
content,
|
|
176
|
+
content: parsed,
|
|
194
177
|
usage: data.usage,
|
|
195
178
|
raw: data,
|
|
196
179
|
};
|
|
@@ -206,20 +189,18 @@ export async function moonshotChat({
|
|
|
206
189
|
if (isContentFilterError(error) && process.env.DEEPSEEK_API_KEY) {
|
|
207
190
|
return fallbackToDeepSeek({
|
|
208
191
|
messages,
|
|
209
|
-
temperature,
|
|
210
192
|
maxTokens,
|
|
211
|
-
responseFormat,
|
|
212
|
-
topP,
|
|
213
|
-
frequencyPenalty,
|
|
214
|
-
presencePenalty,
|
|
215
193
|
stop,
|
|
216
|
-
stream,
|
|
217
194
|
thinking,
|
|
218
195
|
});
|
|
219
196
|
}
|
|
220
197
|
|
|
198
|
+
// Don't retry auth errors
|
|
221
199
|
if (error.status === 401) throw error;
|
|
222
200
|
|
|
201
|
+
// Don't retry JSON parse errors
|
|
202
|
+
if (error instanceof ProviderJsonParseError) throw error;
|
|
203
|
+
|
|
223
204
|
if (isRetryableError(error) && attempt < maxRetries) {
|
|
224
205
|
continue;
|
|
225
206
|
}
|
|
@@ -229,46 +210,4 @@ export async function moonshotChat({
|
|
|
229
210
|
}
|
|
230
211
|
|
|
231
212
|
throw lastError || new Error(`Failed after ${maxRetries + 1} attempts`);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Create async generator for streaming Moonshot responses.
|
|
236
|
-
* Moonshot uses Server-Sent Events format with "data:" prefix.
|
|
237
|
-
*/
|
|
238
|
-
async function* createStreamGenerator(stream) {
|
|
239
|
-
const decoder = new TextDecoder();
|
|
240
|
-
const reader = stream.getReader();
|
|
241
|
-
let buffer = "";
|
|
242
|
-
|
|
243
|
-
try {
|
|
244
|
-
while (true) {
|
|
245
|
-
const { done, value } = await reader.read();
|
|
246
|
-
if (done) break;
|
|
247
|
-
|
|
248
|
-
buffer += decoder.decode(value, { stream: true });
|
|
249
|
-
const lines = buffer.split("\n");
|
|
250
|
-
buffer = lines.pop(); // Keep incomplete line
|
|
251
|
-
|
|
252
|
-
for (const line of lines) {
|
|
253
|
-
if (line.startsWith("data: ")) {
|
|
254
|
-
const data = line.slice(6);
|
|
255
|
-
if (data === "[DONE]") continue;
|
|
256
|
-
|
|
257
|
-
try {
|
|
258
|
-
const parsed = JSON.parse(data);
|
|
259
|
-
const content = parsed.choices?.[0]?.delta?.content;
|
|
260
|
-
// Skip only truly empty chunks; preserve whitespace-only content
|
|
261
|
-
if (content !== undefined && content !== null && content !== "") {
|
|
262
|
-
yield { content };
|
|
263
|
-
}
|
|
264
|
-
} catch (e) {
|
|
265
|
-
// Skip malformed JSON
|
|
266
|
-
logger.warn("Failed to parse stream chunk:", e);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
} finally {
|
|
272
|
-
reader.releaseLock();
|
|
273
|
-
}
|
|
274
|
-
}
|
|
213
|
+
}
|
|
@@ -25647,6 +25647,9 @@ function DAGGrid({
|
|
|
25647
25647
|
if (options?.singleTask) {
|
|
25648
25648
|
restartOptions.singleTask = options.singleTask;
|
|
25649
25649
|
}
|
|
25650
|
+
if (options?.continueAfter) {
|
|
25651
|
+
restartOptions.continueAfter = options.continueAfter;
|
|
25652
|
+
}
|
|
25650
25653
|
await restartJob(jobId, restartOptions);
|
|
25651
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.";
|
|
25652
25655
|
setAlertMessage(successMessage);
|