@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryanfw/prompt-orchestration-pipeline",
3
- "version": "0.17.2",
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 = thinking === "enabled" ? "deepseek-reasoner" : "deepseek-chat";
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 = "moonshot-v1-128k",
56
- temperature = 0.7,
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
- const isJsonMode =
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
- top_p: topP,
109
- frequency_penalty: frequencyPenalty,
110
- presence_penalty: presencePenalty,
111
- stop,
112
- stream,
96
+ response_format: { type: "json_object" },
97
+ thinking: { type: thinking },
98
+ stream: false,
113
99
  };
114
100
 
115
- if (isJsonMode && !stream) {
116
- requestBody.response_format = { type: "json_object" };
101
+ // Only add stop if provided
102
+ if (stop) {
103
+ requestBody.stop = stop;
117
104
  }
118
105
 
119
- logger.log("About to call fetch...");
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
- // Step 6: Handle streaming response path
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("JSON parsed successfully", {
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
- if (isJsonMode) {
176
- const parsed = tryParseJSON(content);
177
- if (!parsed) {
178
- throw new ProviderJsonParseError(
179
- "Moonshot",
180
- model,
181
- content.substring(0, 200),
182
- "Failed to parse JSON response from Moonshot API",
183
- );
184
- }
185
- return {
186
- content: parsed,
187
- usage: data.usage,
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);