@upstash/workflow 0.2.12 → 0.2.14
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/astro.d.mts +2 -2
- package/astro.d.ts +2 -2
- package/astro.js +1254 -1072
- package/astro.mjs +1 -1
- package/{chunk-4GTHIL7S.mjs → chunk-RMS2NQ3K.mjs} +918 -734
- package/cloudflare.d.mts +2 -2
- package/cloudflare.d.ts +2 -2
- package/cloudflare.js +1254 -1072
- package/cloudflare.mjs +1 -1
- package/express.d.mts +2 -2
- package/express.d.ts +2 -2
- package/express.js +1270 -1088
- package/express.mjs +1 -1
- package/h3.d.mts +2 -2
- package/h3.d.ts +2 -2
- package/h3.js +1254 -1072
- package/h3.mjs +1 -1
- package/hono.d.mts +2 -2
- package/hono.d.ts +2 -2
- package/hono.js +1255 -1073
- package/hono.mjs +2 -2
- package/index.d.mts +124 -15
- package/index.d.ts +124 -15
- package/index.js +1259 -1101
- package/index.mjs +32 -56
- package/nextjs.d.mts +2 -2
- package/nextjs.d.ts +2 -2
- package/nextjs.js +1254 -1072
- package/nextjs.mjs +1 -1
- package/package.json +1 -1
- package/{serve-many-DLguU9iR.d.mts → serve-many-BF71QZHQ.d.mts} +1 -1
- package/{serve-many-BdMq5rFX.d.ts → serve-many-BMlN2PAB.d.ts} +1 -1
- package/solidjs.d.mts +1 -1
- package/solidjs.d.ts +1 -1
- package/solidjs.js +1220 -1038
- package/solidjs.mjs +1 -1
- package/svelte.d.mts +2 -2
- package/svelte.d.ts +2 -2
- package/svelte.js +1254 -1072
- package/svelte.mjs +1 -1
- package/{types-D1W0VOpy.d.ts → types-C1WIgVLA.d.mts} +58 -45
- package/{types-D1W0VOpy.d.mts → types-C1WIgVLA.d.ts} +58 -45
|
@@ -42,11 +42,12 @@ var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
|
|
|
42
42
|
var DEFAULT_CONTENT_TYPE = "application/json";
|
|
43
43
|
var NO_CONCURRENCY = 1;
|
|
44
44
|
var DEFAULT_RETRIES = 3;
|
|
45
|
-
var VERSION = "v0.2.
|
|
45
|
+
var VERSION = "v0.2.14";
|
|
46
46
|
var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
|
|
47
47
|
var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
|
|
48
48
|
var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
|
|
49
49
|
var TELEMETRY_HEADER_RUNTIME = "Upstash-Telemetry-Runtime";
|
|
50
|
+
var TELEMETRY_HEADER_AGENT = "Upstash-Telemetry-Agent";
|
|
50
51
|
|
|
51
52
|
// src/error.ts
|
|
52
53
|
import { QstashError } from "@upstash/qstash";
|
|
@@ -101,6 +102,271 @@ var StepTypes = [
|
|
|
101
102
|
"Invoke"
|
|
102
103
|
];
|
|
103
104
|
|
|
105
|
+
// src/agents/adapters.ts
|
|
106
|
+
import { tool } from "ai";
|
|
107
|
+
|
|
108
|
+
// src/agents/constants.ts
|
|
109
|
+
var AGENT_NAME_HEADER = "upstash-agent-name";
|
|
110
|
+
var MANAGER_AGENT_PROMPT = `You are an agent orchestrating other AI Agents.
|
|
111
|
+
|
|
112
|
+
These other agents have tools available to them.
|
|
113
|
+
|
|
114
|
+
Given a prompt, utilize these agents to address requests.
|
|
115
|
+
|
|
116
|
+
Don't always call all the agents provided to you at the same time. You can call one and use it's response to call another.
|
|
117
|
+
|
|
118
|
+
Avoid calling the same agent twice in one turn. Instead, prefer to call it once but provide everything
|
|
119
|
+
you need from that agent.
|
|
120
|
+
`;
|
|
121
|
+
|
|
122
|
+
// src/agents/adapters.ts
|
|
123
|
+
var fetchWithContextCall = async (context, agentCallParams, ...params) => {
|
|
124
|
+
const [input, init] = params;
|
|
125
|
+
try {
|
|
126
|
+
const headers = init?.headers ? Object.fromEntries(new Headers(init.headers).entries()) : {};
|
|
127
|
+
const body = init?.body ? JSON.parse(init.body) : void 0;
|
|
128
|
+
const agentName = headers[AGENT_NAME_HEADER];
|
|
129
|
+
const stepName = agentName ? `Call Agent ${agentName}` : "Call Agent";
|
|
130
|
+
const responseInfo = await context.call(stepName, {
|
|
131
|
+
url: input.toString(),
|
|
132
|
+
method: init?.method,
|
|
133
|
+
headers,
|
|
134
|
+
body,
|
|
135
|
+
timeout: agentCallParams?.timeout,
|
|
136
|
+
retries: agentCallParams?.retries,
|
|
137
|
+
flowControl: agentCallParams?.flowControl
|
|
138
|
+
});
|
|
139
|
+
const responseHeaders = new Headers(
|
|
140
|
+
Object.entries(responseInfo.header).reduce(
|
|
141
|
+
(acc, [key, values]) => {
|
|
142
|
+
acc[key] = values.join(", ");
|
|
143
|
+
return acc;
|
|
144
|
+
},
|
|
145
|
+
{}
|
|
146
|
+
)
|
|
147
|
+
);
|
|
148
|
+
return new Response(JSON.stringify(responseInfo.body), {
|
|
149
|
+
status: responseInfo.status,
|
|
150
|
+
headers: responseHeaders
|
|
151
|
+
});
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (error instanceof Error && error.name === "WorkflowAbort") {
|
|
154
|
+
throw error;
|
|
155
|
+
} else {
|
|
156
|
+
console.error("Error in fetch implementation:", error);
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
var createWorkflowModel = ({
|
|
162
|
+
context,
|
|
163
|
+
provider,
|
|
164
|
+
providerParams,
|
|
165
|
+
agentCallParams
|
|
166
|
+
}) => {
|
|
167
|
+
return provider({
|
|
168
|
+
fetch: (...params) => fetchWithContextCall(context, agentCallParams, ...params),
|
|
169
|
+
...providerParams
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
var wrapTools = ({
|
|
173
|
+
context,
|
|
174
|
+
tools
|
|
175
|
+
}) => {
|
|
176
|
+
return Object.fromEntries(
|
|
177
|
+
Object.entries(tools).map((toolInfo) => {
|
|
178
|
+
const [toolName, tool3] = toolInfo;
|
|
179
|
+
const executeAsStep = "executeAsStep" in tool3 ? tool3.executeAsStep : true;
|
|
180
|
+
const aiSDKTool = convertToAISDKTool(tool3);
|
|
181
|
+
const execute = aiSDKTool.execute;
|
|
182
|
+
if (execute && executeAsStep) {
|
|
183
|
+
const wrappedExecute = (...params) => {
|
|
184
|
+
return context.run(`Run tool ${toolName}`, () => execute(...params));
|
|
185
|
+
};
|
|
186
|
+
aiSDKTool.execute = wrappedExecute;
|
|
187
|
+
}
|
|
188
|
+
return [toolName, aiSDKTool];
|
|
189
|
+
})
|
|
190
|
+
);
|
|
191
|
+
};
|
|
192
|
+
var convertToAISDKTool = (tool3) => {
|
|
193
|
+
const isLangchainTool = "invoke" in tool3;
|
|
194
|
+
return isLangchainTool ? convertLangchainTool(tool3) : tool3;
|
|
195
|
+
};
|
|
196
|
+
var convertLangchainTool = (langchainTool) => {
|
|
197
|
+
return tool({
|
|
198
|
+
description: langchainTool.description,
|
|
199
|
+
parameters: langchainTool.schema,
|
|
200
|
+
execute: async (...param) => langchainTool.invoke(...param)
|
|
201
|
+
});
|
|
202
|
+
};
|
|
203
|
+
var WorkflowTool = class {
|
|
204
|
+
/**
|
|
205
|
+
* description of the tool
|
|
206
|
+
*/
|
|
207
|
+
description;
|
|
208
|
+
/**
|
|
209
|
+
* schema of the tool
|
|
210
|
+
*/
|
|
211
|
+
schema;
|
|
212
|
+
/**
|
|
213
|
+
* function to invoke the tool
|
|
214
|
+
*/
|
|
215
|
+
invoke;
|
|
216
|
+
/**
|
|
217
|
+
* whether the invoke method of the tool is to be wrapped with `context.run`
|
|
218
|
+
*/
|
|
219
|
+
executeAsStep;
|
|
220
|
+
/**
|
|
221
|
+
*
|
|
222
|
+
* @param description description of the tool
|
|
223
|
+
* @param schema schema of the tool
|
|
224
|
+
* @param invoke function to invoke the tool
|
|
225
|
+
* @param executeAsStep whether the invoke method of the tool is to be wrapped with `context.run`
|
|
226
|
+
*/
|
|
227
|
+
constructor(params) {
|
|
228
|
+
this.description = params.description;
|
|
229
|
+
this.schema = params.schema;
|
|
230
|
+
this.invoke = params.invoke;
|
|
231
|
+
this.executeAsStep = params.executeAsStep ?? true;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// src/serve/serve-many.ts
|
|
236
|
+
var getWorkflowId = (url) => {
|
|
237
|
+
const components = url.split("/");
|
|
238
|
+
const lastComponent = components[components.length - 1];
|
|
239
|
+
return lastComponent.split("?")[0];
|
|
240
|
+
};
|
|
241
|
+
var serveManyBase = ({
|
|
242
|
+
workflows,
|
|
243
|
+
getUrl,
|
|
244
|
+
serveMethod,
|
|
245
|
+
options
|
|
246
|
+
}) => {
|
|
247
|
+
const workflowIds = [];
|
|
248
|
+
const workflowMap = Object.fromEntries(
|
|
249
|
+
Object.entries(workflows).map((workflow) => {
|
|
250
|
+
const workflowId = workflow[0];
|
|
251
|
+
if (workflowIds.includes(workflowId)) {
|
|
252
|
+
throw new WorkflowError(
|
|
253
|
+
`Duplicate workflow name found: '${workflowId}'. Please set different workflow names in serveMany.`
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
if (workflowId.includes("/")) {
|
|
257
|
+
throw new WorkflowError(
|
|
258
|
+
`Invalid workflow name found: '${workflowId}'. Workflow name cannot contain '/'.`
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
workflowIds.push(workflowId);
|
|
262
|
+
workflow[1].workflowId = workflowId;
|
|
263
|
+
workflow[1].options = {
|
|
264
|
+
...options,
|
|
265
|
+
...workflow[1].options
|
|
266
|
+
};
|
|
267
|
+
const params = [workflow[1].routeFunction, workflow[1].options];
|
|
268
|
+
const handler = serveMethod(...params);
|
|
269
|
+
return [workflowId, handler];
|
|
270
|
+
})
|
|
271
|
+
);
|
|
272
|
+
return {
|
|
273
|
+
handler: async (...params) => {
|
|
274
|
+
const url = getUrl(...params);
|
|
275
|
+
const pickedWorkflowId = getWorkflowId(url);
|
|
276
|
+
if (!pickedWorkflowId) {
|
|
277
|
+
return new Response(
|
|
278
|
+
`Unexpected request in serveMany. workflowId not set. Please update the URL of your request.`,
|
|
279
|
+
{
|
|
280
|
+
status: 404
|
|
281
|
+
}
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
const workflow = workflowMap[pickedWorkflowId];
|
|
285
|
+
if (!workflow) {
|
|
286
|
+
return new Response(
|
|
287
|
+
`No workflows in serveMany found for '${pickedWorkflowId}'. Please update the URL of your request.`,
|
|
288
|
+
{
|
|
289
|
+
status: 404
|
|
290
|
+
}
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
return await workflow(...params);
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
};
|
|
297
|
+
var getNewUrlFromWorkflowId = (url, workflowId) => {
|
|
298
|
+
if (!workflowId) {
|
|
299
|
+
throw new WorkflowError("You can only call workflow which has a workflowId");
|
|
300
|
+
}
|
|
301
|
+
return url.replace(/[^/]+$/, workflowId);
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
// src/context/auto-executor.ts
|
|
305
|
+
import { QstashError as QstashError5 } from "@upstash/qstash";
|
|
306
|
+
|
|
307
|
+
// src/qstash/headers.ts
|
|
308
|
+
import { QstashError as QstashError4 } from "@upstash/qstash";
|
|
309
|
+
|
|
310
|
+
// src/client/utils.ts
|
|
311
|
+
import { QstashError as QstashError2 } from "@upstash/qstash";
|
|
312
|
+
var makeNotifyRequest = async (requester, eventId, eventData) => {
|
|
313
|
+
const result = await requester.request({
|
|
314
|
+
path: ["v2", "notify", eventId],
|
|
315
|
+
method: "POST",
|
|
316
|
+
body: typeof eventData === "string" ? eventData : JSON.stringify(eventData)
|
|
317
|
+
});
|
|
318
|
+
return result;
|
|
319
|
+
};
|
|
320
|
+
var makeGetWaitersRequest = async (requester, eventId) => {
|
|
321
|
+
const result = await requester.request({
|
|
322
|
+
path: ["v2", "waiters", eventId],
|
|
323
|
+
method: "GET"
|
|
324
|
+
});
|
|
325
|
+
return result;
|
|
326
|
+
};
|
|
327
|
+
var makeCancelRequest = async (requester, workflowRunId) => {
|
|
328
|
+
await requester.request({
|
|
329
|
+
path: ["v2", "workflows", "runs", `${workflowRunId}?cancel=true`],
|
|
330
|
+
method: "DELETE",
|
|
331
|
+
parseResponseAsJson: false
|
|
332
|
+
});
|
|
333
|
+
return true;
|
|
334
|
+
};
|
|
335
|
+
var getSteps = async (requester, workflowRunId, messageId, debug) => {
|
|
336
|
+
try {
|
|
337
|
+
const steps = await requester.request({
|
|
338
|
+
path: ["v2", "workflows", "runs", workflowRunId],
|
|
339
|
+
parseResponseAsJson: true
|
|
340
|
+
});
|
|
341
|
+
if (!messageId) {
|
|
342
|
+
await debug?.log("INFO", "ENDPOINT_START", {
|
|
343
|
+
message: `Pulled ${steps.length} steps from QStashand returned them without filtering with messageId.`
|
|
344
|
+
});
|
|
345
|
+
return { steps, workflowRunEnded: false };
|
|
346
|
+
} else {
|
|
347
|
+
const index = steps.findIndex((item) => item.messageId === messageId);
|
|
348
|
+
if (index === -1) {
|
|
349
|
+
return { steps: [], workflowRunEnded: false };
|
|
350
|
+
}
|
|
351
|
+
const filteredSteps = steps.slice(0, index + 1);
|
|
352
|
+
await debug?.log("INFO", "ENDPOINT_START", {
|
|
353
|
+
message: `Pulled ${steps.length} steps from QStash and filtered them to ${filteredSteps.length} using messageId.`
|
|
354
|
+
});
|
|
355
|
+
return { steps: filteredSteps, workflowRunEnded: false };
|
|
356
|
+
}
|
|
357
|
+
} catch (error) {
|
|
358
|
+
if (error instanceof QstashError2 && error.status === 404) {
|
|
359
|
+
await debug?.log("WARN", "ENDPOINT_START", {
|
|
360
|
+
message: "Couldn't fetch workflow run steps. This can happen if the workflow run succesfully ends before some callback is executed.",
|
|
361
|
+
error
|
|
362
|
+
});
|
|
363
|
+
return { steps: void 0, workflowRunEnded: true };
|
|
364
|
+
} else {
|
|
365
|
+
throw error;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
|
|
104
370
|
// src/utils.ts
|
|
105
371
|
var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
|
|
106
372
|
var NANOID_LENGTH = 21;
|
|
@@ -543,116 +809,72 @@ var fromThrowable = Result.fromThrowable;
|
|
|
543
809
|
|
|
544
810
|
// src/workflow-requests.ts
|
|
545
811
|
import { QstashError as QstashError3 } from "@upstash/qstash";
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
var makeCancelRequest = async (requester, workflowRunId) => {
|
|
565
|
-
await requester.request({
|
|
566
|
-
path: ["v2", "workflows", "runs", `${workflowRunId}?cancel=true`],
|
|
567
|
-
method: "DELETE",
|
|
568
|
-
parseResponseAsJson: false
|
|
569
|
-
});
|
|
570
|
-
return true;
|
|
571
|
-
};
|
|
572
|
-
var getSteps = async (requester, workflowRunId, messageId, debug) => {
|
|
573
|
-
try {
|
|
574
|
-
const steps = await requester.request({
|
|
575
|
-
path: ["v2", "workflows", "runs", workflowRunId],
|
|
576
|
-
parseResponseAsJson: true
|
|
577
|
-
});
|
|
578
|
-
if (!messageId) {
|
|
579
|
-
await debug?.log("INFO", "ENDPOINT_START", {
|
|
580
|
-
message: `Pulled ${steps.length} steps from QStashand returned them without filtering with messageId.`
|
|
812
|
+
var triggerFirstInvocation = async (params) => {
|
|
813
|
+
const firstInvocationParams = Array.isArray(params) ? params : [params];
|
|
814
|
+
const workflowContextClient = firstInvocationParams[0].workflowContext.qstashClient;
|
|
815
|
+
const invocationBatch = firstInvocationParams.map(
|
|
816
|
+
({ workflowContext, useJSONContent, telemetry, invokeCount, delay }) => {
|
|
817
|
+
const { headers } = getHeaders({
|
|
818
|
+
initHeaderValue: "true",
|
|
819
|
+
workflowConfig: {
|
|
820
|
+
workflowRunId: workflowContext.workflowRunId,
|
|
821
|
+
workflowUrl: workflowContext.url,
|
|
822
|
+
failureUrl: workflowContext.failureUrl,
|
|
823
|
+
retries: workflowContext.retries,
|
|
824
|
+
telemetry,
|
|
825
|
+
flowControl: workflowContext.flowControl,
|
|
826
|
+
useJSONContent: useJSONContent ?? false
|
|
827
|
+
},
|
|
828
|
+
invokeCount: invokeCount ?? 0,
|
|
829
|
+
userHeaders: workflowContext.headers
|
|
581
830
|
});
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
const index = steps.findIndex((item) => item.messageId === messageId);
|
|
585
|
-
if (index === -1) {
|
|
586
|
-
return { steps: [], workflowRunEnded: false };
|
|
831
|
+
if (workflowContext.headers.get("content-type")) {
|
|
832
|
+
headers["content-type"] = workflowContext.headers.get("content-type");
|
|
587
833
|
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
return {
|
|
593
|
-
}
|
|
594
|
-
} catch (error) {
|
|
595
|
-
if (error instanceof QstashError2 && error.status === 404) {
|
|
596
|
-
await debug?.log("WARN", "ENDPOINT_START", {
|
|
597
|
-
message: "Couldn't fetch workflow run steps. This can happen if the workflow run succesfully ends before some callback is executed.",
|
|
598
|
-
error
|
|
599
|
-
});
|
|
600
|
-
return { steps: void 0, workflowRunEnded: true };
|
|
601
|
-
} else {
|
|
602
|
-
throw error;
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
};
|
|
606
|
-
|
|
607
|
-
// src/workflow-requests.ts
|
|
608
|
-
var triggerFirstInvocation = async ({
|
|
609
|
-
workflowContext,
|
|
610
|
-
useJSONContent,
|
|
611
|
-
telemetry,
|
|
612
|
-
debug,
|
|
613
|
-
invokeCount
|
|
614
|
-
}) => {
|
|
615
|
-
const { headers } = getHeaders({
|
|
616
|
-
initHeaderValue: "true",
|
|
617
|
-
workflowRunId: workflowContext.workflowRunId,
|
|
618
|
-
workflowUrl: workflowContext.url,
|
|
619
|
-
userHeaders: workflowContext.headers,
|
|
620
|
-
failureUrl: workflowContext.failureUrl,
|
|
621
|
-
retries: workflowContext.retries,
|
|
622
|
-
telemetry,
|
|
623
|
-
invokeCount,
|
|
624
|
-
flowControl: workflowContext.flowControl
|
|
625
|
-
});
|
|
626
|
-
if (workflowContext.headers.get("content-type")) {
|
|
627
|
-
headers["content-type"] = workflowContext.headers.get("content-type");
|
|
628
|
-
}
|
|
629
|
-
if (useJSONContent) {
|
|
630
|
-
headers["content-type"] = "application/json";
|
|
631
|
-
}
|
|
632
|
-
try {
|
|
633
|
-
const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
|
|
634
|
-
const result = await workflowContext.qstashClient.publish({
|
|
635
|
-
headers,
|
|
636
|
-
method: "POST",
|
|
637
|
-
body,
|
|
638
|
-
url: workflowContext.url
|
|
639
|
-
});
|
|
640
|
-
if (result.deduplicated) {
|
|
641
|
-
await debug?.log("WARN", "SUBMIT_FIRST_INVOCATION", {
|
|
642
|
-
message: `Workflow run ${workflowContext.workflowRunId} already exists. A new one isn't created.`,
|
|
834
|
+
if (useJSONContent) {
|
|
835
|
+
headers["content-type"] = "application/json";
|
|
836
|
+
}
|
|
837
|
+
const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
|
|
838
|
+
return {
|
|
643
839
|
headers,
|
|
644
|
-
|
|
840
|
+
method: "POST",
|
|
841
|
+
body,
|
|
645
842
|
url: workflowContext.url,
|
|
646
|
-
|
|
647
|
-
}
|
|
843
|
+
delay
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
);
|
|
847
|
+
try {
|
|
848
|
+
const results = await workflowContextClient.batch(invocationBatch);
|
|
849
|
+
const invocationStatuses = [];
|
|
850
|
+
for (let i = 0; i < results.length; i++) {
|
|
851
|
+
const result = results[i];
|
|
852
|
+
const invocationParams = firstInvocationParams[i];
|
|
853
|
+
if (result.deduplicated) {
|
|
854
|
+
await invocationParams.debug?.log("WARN", "SUBMIT_FIRST_INVOCATION", {
|
|
855
|
+
message: `Workflow run ${invocationParams.workflowContext.workflowRunId} already exists. A new one isn't created.`,
|
|
856
|
+
headers: invocationBatch[i].headers,
|
|
857
|
+
requestPayload: invocationParams.workflowContext.requestPayload,
|
|
858
|
+
url: invocationParams.workflowContext.url,
|
|
859
|
+
messageId: result.messageId
|
|
860
|
+
});
|
|
861
|
+
invocationStatuses.push("workflow-run-already-exists");
|
|
862
|
+
} else {
|
|
863
|
+
await invocationParams.debug?.log("SUBMIT", "SUBMIT_FIRST_INVOCATION", {
|
|
864
|
+
headers: invocationBatch[i].headers,
|
|
865
|
+
requestPayload: invocationParams.workflowContext.requestPayload,
|
|
866
|
+
url: invocationParams.workflowContext.url,
|
|
867
|
+
messageId: result.messageId
|
|
868
|
+
});
|
|
869
|
+
invocationStatuses.push("success");
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
const hasAnyDeduplicated = invocationStatuses.some(
|
|
873
|
+
(status) => status === "workflow-run-already-exists"
|
|
874
|
+
);
|
|
875
|
+
if (hasAnyDeduplicated) {
|
|
648
876
|
return ok("workflow-run-already-exists");
|
|
649
877
|
} else {
|
|
650
|
-
await debug?.log("SUBMIT", "SUBMIT_FIRST_INVOCATION", {
|
|
651
|
-
headers,
|
|
652
|
-
requestPayload: workflowContext.requestPayload,
|
|
653
|
-
url: workflowContext.url,
|
|
654
|
-
messageId: result.messageId
|
|
655
|
-
});
|
|
656
878
|
return ok("success");
|
|
657
879
|
}
|
|
658
880
|
} catch (error) {
|
|
@@ -791,14 +1013,16 @@ ${atob(callbackMessage.body ?? "")}`
|
|
|
791
1013
|
const userHeaders = recreateUserHeaders(request.headers);
|
|
792
1014
|
const { headers: requestHeaders } = getHeaders({
|
|
793
1015
|
initHeaderValue: "false",
|
|
794
|
-
|
|
795
|
-
|
|
1016
|
+
workflowConfig: {
|
|
1017
|
+
workflowRunId,
|
|
1018
|
+
workflowUrl,
|
|
1019
|
+
failureUrl,
|
|
1020
|
+
retries,
|
|
1021
|
+
telemetry,
|
|
1022
|
+
flowControl
|
|
1023
|
+
},
|
|
796
1024
|
userHeaders,
|
|
797
|
-
|
|
798
|
-
retries,
|
|
799
|
-
telemetry,
|
|
800
|
-
invokeCount: Number(invokeCount),
|
|
801
|
-
flowControl
|
|
1025
|
+
invokeCount: Number(invokeCount)
|
|
802
1026
|
});
|
|
803
1027
|
const callResponse = {
|
|
804
1028
|
status: callbackMessage.status,
|
|
@@ -844,154 +1068,6 @@ var getTelemetryHeaders = (telemetry) => {
|
|
|
844
1068
|
[TELEMETRY_HEADER_RUNTIME]: telemetry.runtime ?? "unknown"
|
|
845
1069
|
};
|
|
846
1070
|
};
|
|
847
|
-
var getHeaders = ({
|
|
848
|
-
initHeaderValue,
|
|
849
|
-
workflowRunId,
|
|
850
|
-
workflowUrl,
|
|
851
|
-
userHeaders,
|
|
852
|
-
failureUrl,
|
|
853
|
-
retries,
|
|
854
|
-
step,
|
|
855
|
-
callRetries,
|
|
856
|
-
callTimeout,
|
|
857
|
-
telemetry,
|
|
858
|
-
invokeCount,
|
|
859
|
-
flowControl,
|
|
860
|
-
callFlowControl
|
|
861
|
-
}) => {
|
|
862
|
-
const callHeaders = new Headers(step?.callHeaders);
|
|
863
|
-
const contentType = (callHeaders.get("content-type") ? callHeaders.get("content-type") : userHeaders?.get("Content-Type") ? userHeaders.get("Content-Type") : void 0) ?? DEFAULT_CONTENT_TYPE;
|
|
864
|
-
const baseHeaders = {
|
|
865
|
-
[WORKFLOW_INIT_HEADER]: initHeaderValue,
|
|
866
|
-
[WORKFLOW_ID_HEADER]: workflowRunId,
|
|
867
|
-
[WORKFLOW_URL_HEADER]: workflowUrl,
|
|
868
|
-
[WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody",
|
|
869
|
-
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
|
|
870
|
-
"content-type": contentType,
|
|
871
|
-
...telemetry ? getTelemetryHeaders(telemetry) : {}
|
|
872
|
-
};
|
|
873
|
-
if (invokeCount !== void 0 && !step?.callUrl) {
|
|
874
|
-
baseHeaders[`Upstash-Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`] = invokeCount.toString();
|
|
875
|
-
}
|
|
876
|
-
if (!step?.callUrl) {
|
|
877
|
-
baseHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
|
|
878
|
-
}
|
|
879
|
-
if (callTimeout) {
|
|
880
|
-
baseHeaders[`Upstash-Timeout`] = callTimeout.toString();
|
|
881
|
-
}
|
|
882
|
-
if (failureUrl) {
|
|
883
|
-
baseHeaders[`Upstash-Failure-Callback-Forward-${WORKFLOW_FAILURE_HEADER}`] = "true";
|
|
884
|
-
baseHeaders[`Upstash-Failure-Callback-Forward-Upstash-Workflow-Failure-Callback`] = "true";
|
|
885
|
-
baseHeaders["Upstash-Failure-Callback-Workflow-Runid"] = workflowRunId;
|
|
886
|
-
baseHeaders["Upstash-Failure-Callback-Workflow-Init"] = "false";
|
|
887
|
-
baseHeaders["Upstash-Failure-Callback-Workflow-Url"] = workflowUrl;
|
|
888
|
-
baseHeaders["Upstash-Failure-Callback-Workflow-Calltype"] = "failureCall";
|
|
889
|
-
if (retries !== void 0) {
|
|
890
|
-
baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
|
|
891
|
-
}
|
|
892
|
-
if (flowControl) {
|
|
893
|
-
const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
|
|
894
|
-
baseHeaders["Upstash-Failure-Callback-Flow-Control-Key"] = flowControlKey;
|
|
895
|
-
baseHeaders["Upstash-Failure-Callback-Flow-Control-Value"] = flowControlValue;
|
|
896
|
-
}
|
|
897
|
-
if (!step?.callUrl) {
|
|
898
|
-
baseHeaders["Upstash-Failure-Callback"] = failureUrl;
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
if (step?.callUrl) {
|
|
902
|
-
baseHeaders["Upstash-Retries"] = callRetries?.toString() ?? "0";
|
|
903
|
-
baseHeaders[WORKFLOW_FEATURE_HEADER] = "WF_NoDelete,InitialBody";
|
|
904
|
-
if (retries !== void 0) {
|
|
905
|
-
baseHeaders["Upstash-Callback-Retries"] = retries.toString();
|
|
906
|
-
baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
|
|
907
|
-
}
|
|
908
|
-
if (callFlowControl) {
|
|
909
|
-
const { flowControlKey, flowControlValue } = prepareFlowControl(callFlowControl);
|
|
910
|
-
baseHeaders["Upstash-Flow-Control-Key"] = flowControlKey;
|
|
911
|
-
baseHeaders["Upstash-Flow-Control-Value"] = flowControlValue;
|
|
912
|
-
}
|
|
913
|
-
if (flowControl) {
|
|
914
|
-
const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
|
|
915
|
-
baseHeaders["Upstash-Callback-Flow-Control-Key"] = flowControlKey;
|
|
916
|
-
baseHeaders["Upstash-Callback-Flow-Control-Value"] = flowControlValue;
|
|
917
|
-
}
|
|
918
|
-
} else {
|
|
919
|
-
if (flowControl) {
|
|
920
|
-
const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
|
|
921
|
-
baseHeaders["Upstash-Flow-Control-Key"] = flowControlKey;
|
|
922
|
-
baseHeaders["Upstash-Flow-Control-Value"] = flowControlValue;
|
|
923
|
-
}
|
|
924
|
-
if (retries !== void 0) {
|
|
925
|
-
baseHeaders["Upstash-Retries"] = retries.toString();
|
|
926
|
-
baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
if (userHeaders) {
|
|
930
|
-
for (const header of userHeaders.keys()) {
|
|
931
|
-
if (step?.callHeaders) {
|
|
932
|
-
baseHeaders[`Upstash-Callback-Forward-${header}`] = userHeaders.get(header);
|
|
933
|
-
} else {
|
|
934
|
-
baseHeaders[`Upstash-Forward-${header}`] = userHeaders.get(header);
|
|
935
|
-
}
|
|
936
|
-
baseHeaders[`Upstash-Failure-Callback-Forward-${header}`] = userHeaders.get(header);
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
if (step?.callHeaders) {
|
|
940
|
-
const forwardedHeaders = Object.fromEntries(
|
|
941
|
-
Object.entries(step.callHeaders).map(([header, value]) => [
|
|
942
|
-
`Upstash-Forward-${header}`,
|
|
943
|
-
value
|
|
944
|
-
])
|
|
945
|
-
);
|
|
946
|
-
return {
|
|
947
|
-
headers: {
|
|
948
|
-
...baseHeaders,
|
|
949
|
-
...forwardedHeaders,
|
|
950
|
-
"Upstash-Callback": workflowUrl,
|
|
951
|
-
"Upstash-Callback-Workflow-RunId": workflowRunId,
|
|
952
|
-
"Upstash-Callback-Workflow-CallType": "fromCallback",
|
|
953
|
-
"Upstash-Callback-Workflow-Init": "false",
|
|
954
|
-
"Upstash-Callback-Workflow-Url": workflowUrl,
|
|
955
|
-
"Upstash-Callback-Feature-Set": "LazyFetch,InitialBody",
|
|
956
|
-
"Upstash-Callback-Forward-Upstash-Workflow-Callback": "true",
|
|
957
|
-
"Upstash-Callback-Forward-Upstash-Workflow-StepId": step.stepId.toString(),
|
|
958
|
-
"Upstash-Callback-Forward-Upstash-Workflow-StepName": step.stepName,
|
|
959
|
-
"Upstash-Callback-Forward-Upstash-Workflow-StepType": step.stepType,
|
|
960
|
-
"Upstash-Callback-Forward-Upstash-Workflow-Concurrent": step.concurrent.toString(),
|
|
961
|
-
"Upstash-Callback-Forward-Upstash-Workflow-ContentType": contentType,
|
|
962
|
-
[`Upstash-Callback-Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`]: (invokeCount ?? 0).toString(),
|
|
963
|
-
"Upstash-Workflow-CallType": "toCallback"
|
|
964
|
-
}
|
|
965
|
-
};
|
|
966
|
-
}
|
|
967
|
-
if (step?.waitEventId) {
|
|
968
|
-
return {
|
|
969
|
-
headers: {
|
|
970
|
-
...baseHeaders,
|
|
971
|
-
"Upstash-Workflow-CallType": "step"
|
|
972
|
-
},
|
|
973
|
-
timeoutHeaders: {
|
|
974
|
-
// to include user headers:
|
|
975
|
-
...Object.fromEntries(
|
|
976
|
-
Object.entries(baseHeaders).map(([header, value]) => [header, [value]])
|
|
977
|
-
),
|
|
978
|
-
// to include telemetry headers:
|
|
979
|
-
...telemetry ? Object.fromEntries(
|
|
980
|
-
Object.entries(getTelemetryHeaders(telemetry)).map(([header, value]) => [
|
|
981
|
-
header,
|
|
982
|
-
[value]
|
|
983
|
-
])
|
|
984
|
-
) : {},
|
|
985
|
-
// note: using WORKFLOW_ID_HEADER doesn't work, because Runid -> RunId:
|
|
986
|
-
"Upstash-Workflow-Runid": [workflowRunId],
|
|
987
|
-
[WORKFLOW_INIT_HEADER]: ["false"],
|
|
988
|
-
[WORKFLOW_URL_HEADER]: [workflowUrl],
|
|
989
|
-
"Upstash-Workflow-CallType": ["step"]
|
|
990
|
-
}
|
|
991
|
-
};
|
|
992
|
-
}
|
|
993
|
-
return { headers: baseHeaders };
|
|
994
|
-
};
|
|
995
1071
|
var verifyRequest = async (body, signature, verifier) => {
|
|
996
1072
|
if (!verifier) {
|
|
997
1073
|
return;
|
|
@@ -1010,286 +1086,11 @@ var verifyRequest = async (body, signature, verifier) => {
|
|
|
1010
1086
|
} catch (error) {
|
|
1011
1087
|
throw new WorkflowError(
|
|
1012
1088
|
`Failed to verify that the Workflow request comes from QStash: ${error}
|
|
1013
|
-
|
|
1014
|
-
If signature is missing, trigger the workflow endpoint by publishing your request to QStash instead of calling it directly.
|
|
1015
|
-
|
|
1016
|
-
If you want to disable QStash Verification, you should clear env variables QSTASH_CURRENT_SIGNING_KEY and QSTASH_NEXT_SIGNING_KEY`
|
|
1017
|
-
);
|
|
1018
|
-
}
|
|
1019
|
-
};
|
|
1020
|
-
var prepareFlowControl = (flowControl) => {
|
|
1021
|
-
const parallelism = flowControl.parallelism?.toString();
|
|
1022
|
-
const rate = flowControl.ratePerSecond?.toString();
|
|
1023
|
-
const controlValue = [
|
|
1024
|
-
parallelism ? `parallelism=${parallelism}` : void 0,
|
|
1025
|
-
rate ? `rate=${rate}` : void 0
|
|
1026
|
-
].filter(Boolean);
|
|
1027
|
-
if (controlValue.length === 0) {
|
|
1028
|
-
throw new QstashError3("Provide at least one of parallelism or ratePerSecond for flowControl");
|
|
1029
|
-
}
|
|
1030
|
-
return {
|
|
1031
|
-
flowControlKey: flowControl.key,
|
|
1032
|
-
flowControlValue: controlValue.join(", ")
|
|
1033
|
-
};
|
|
1034
|
-
};
|
|
1035
|
-
|
|
1036
|
-
// src/serve/serve-many.ts
|
|
1037
|
-
var getWorkflowId = (url) => {
|
|
1038
|
-
const components = url.split("/");
|
|
1039
|
-
const lastComponent = components[components.length - 1];
|
|
1040
|
-
return lastComponent.split("?")[0];
|
|
1041
|
-
};
|
|
1042
|
-
var serveManyBase = ({
|
|
1043
|
-
workflows,
|
|
1044
|
-
getUrl,
|
|
1045
|
-
serveMethod,
|
|
1046
|
-
options
|
|
1047
|
-
}) => {
|
|
1048
|
-
const workflowIds = [];
|
|
1049
|
-
const workflowMap = Object.fromEntries(
|
|
1050
|
-
Object.entries(workflows).map((workflow) => {
|
|
1051
|
-
const workflowId = workflow[0];
|
|
1052
|
-
if (workflowIds.includes(workflowId)) {
|
|
1053
|
-
throw new WorkflowError(
|
|
1054
|
-
`Duplicate workflow name found: '${workflowId}'. Please set different workflow names in serveMany.`
|
|
1055
|
-
);
|
|
1056
|
-
}
|
|
1057
|
-
if (workflowId.includes("/")) {
|
|
1058
|
-
throw new WorkflowError(
|
|
1059
|
-
`Invalid workflow name found: '${workflowId}'. Workflow name cannot contain '/'.`
|
|
1060
|
-
);
|
|
1061
|
-
}
|
|
1062
|
-
workflowIds.push(workflowId);
|
|
1063
|
-
workflow[1].workflowId = workflowId;
|
|
1064
|
-
workflow[1].options = {
|
|
1065
|
-
...options,
|
|
1066
|
-
...workflow[1].options
|
|
1067
|
-
};
|
|
1068
|
-
const params = [workflow[1].routeFunction, workflow[1].options];
|
|
1069
|
-
const handler = serveMethod(...params);
|
|
1070
|
-
return [workflowId, handler];
|
|
1071
|
-
})
|
|
1072
|
-
);
|
|
1073
|
-
return {
|
|
1074
|
-
handler: async (...params) => {
|
|
1075
|
-
const url = getUrl(...params);
|
|
1076
|
-
const pickedWorkflowId = getWorkflowId(url);
|
|
1077
|
-
if (!pickedWorkflowId) {
|
|
1078
|
-
return new Response(
|
|
1079
|
-
`Unexpected request in serveMany. workflowId not set. Please update the URL of your request.`,
|
|
1080
|
-
{
|
|
1081
|
-
status: 404
|
|
1082
|
-
}
|
|
1083
|
-
);
|
|
1084
|
-
}
|
|
1085
|
-
const workflow = workflowMap[pickedWorkflowId];
|
|
1086
|
-
if (!workflow) {
|
|
1087
|
-
return new Response(
|
|
1088
|
-
`No workflows in serveMany found for '${pickedWorkflowId}'. Please update the URL of your request.`,
|
|
1089
|
-
{
|
|
1090
|
-
status: 404
|
|
1091
|
-
}
|
|
1092
|
-
);
|
|
1093
|
-
}
|
|
1094
|
-
return await workflow(...params);
|
|
1095
|
-
}
|
|
1096
|
-
};
|
|
1097
|
-
};
|
|
1098
|
-
var invokeWorkflow = async ({
|
|
1099
|
-
settings,
|
|
1100
|
-
invokeStep,
|
|
1101
|
-
context,
|
|
1102
|
-
invokeCount,
|
|
1103
|
-
telemetry
|
|
1104
|
-
}) => {
|
|
1105
|
-
const {
|
|
1106
|
-
body,
|
|
1107
|
-
workflow,
|
|
1108
|
-
headers = {},
|
|
1109
|
-
workflowRunId = getWorkflowRunId(),
|
|
1110
|
-
retries,
|
|
1111
|
-
flowControl
|
|
1112
|
-
} = settings;
|
|
1113
|
-
const { workflowId } = workflow;
|
|
1114
|
-
const {
|
|
1115
|
-
retries: workflowRetries,
|
|
1116
|
-
failureFunction,
|
|
1117
|
-
failureUrl,
|
|
1118
|
-
useJSONContent,
|
|
1119
|
-
flowControl: workflowFlowControl
|
|
1120
|
-
} = workflow.options;
|
|
1121
|
-
if (!workflowId) {
|
|
1122
|
-
throw new WorkflowError("You can only invoke workflow which has a workflowId");
|
|
1123
|
-
}
|
|
1124
|
-
const { headers: invokerHeaders } = getHeaders({
|
|
1125
|
-
initHeaderValue: "false",
|
|
1126
|
-
workflowRunId: context.workflowRunId,
|
|
1127
|
-
workflowUrl: context.url,
|
|
1128
|
-
userHeaders: context.headers,
|
|
1129
|
-
failureUrl: context.failureUrl,
|
|
1130
|
-
retries: context.retries,
|
|
1131
|
-
telemetry,
|
|
1132
|
-
invokeCount,
|
|
1133
|
-
flowControl: context.flowControl
|
|
1134
|
-
});
|
|
1135
|
-
invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
|
|
1136
|
-
const newUrl = context.url.replace(/[^/]+$/, workflowId);
|
|
1137
|
-
const { headers: triggerHeaders } = getHeaders({
|
|
1138
|
-
initHeaderValue: "true",
|
|
1139
|
-
workflowRunId,
|
|
1140
|
-
workflowUrl: newUrl,
|
|
1141
|
-
userHeaders: new Headers(headers),
|
|
1142
|
-
retries: retries ?? workflowRetries,
|
|
1143
|
-
telemetry,
|
|
1144
|
-
failureUrl: failureFunction ? newUrl : failureUrl,
|
|
1145
|
-
invokeCount: invokeCount + 1,
|
|
1146
|
-
flowControl: flowControl ?? workflowFlowControl
|
|
1147
|
-
});
|
|
1148
|
-
triggerHeaders["Upstash-Workflow-Invoke"] = "true";
|
|
1149
|
-
if (useJSONContent) {
|
|
1150
|
-
triggerHeaders["content-type"] = "application/json";
|
|
1151
|
-
}
|
|
1152
|
-
const request = {
|
|
1153
|
-
body: JSON.stringify(body),
|
|
1154
|
-
headers: Object.fromEntries(
|
|
1155
|
-
Object.entries(invokerHeaders).map((pairs) => [pairs[0], [pairs[1]]])
|
|
1156
|
-
),
|
|
1157
|
-
workflowRunId: context.workflowRunId,
|
|
1158
|
-
workflowUrl: context.url,
|
|
1159
|
-
step: invokeStep
|
|
1160
|
-
};
|
|
1161
|
-
await context.qstashClient.publish({
|
|
1162
|
-
headers: triggerHeaders,
|
|
1163
|
-
method: "POST",
|
|
1164
|
-
body: JSON.stringify(request),
|
|
1165
|
-
url: newUrl
|
|
1166
|
-
});
|
|
1167
|
-
};
|
|
1168
|
-
|
|
1169
|
-
// src/agents/adapters.ts
|
|
1170
|
-
import { createOpenAI } from "@ai-sdk/openai";
|
|
1171
|
-
import { tool } from "ai";
|
|
1172
|
-
|
|
1173
|
-
// src/agents/constants.ts
|
|
1174
|
-
var AGENT_NAME_HEADER = "upstash-agent-name";
|
|
1175
|
-
var MANAGER_AGENT_PROMPT = `You are an agent orchestrating other AI Agents.
|
|
1176
|
-
|
|
1177
|
-
These other agents have tools available to them.
|
|
1178
|
-
|
|
1179
|
-
Given a prompt, utilize these agents to address requests.
|
|
1180
|
-
|
|
1181
|
-
Don't always call all the agents provided to you at the same time. You can call one and use it's response to call another.
|
|
1182
|
-
|
|
1183
|
-
Avoid calling the same agent twice in one turn. Instead, prefer to call it once but provide everything
|
|
1184
|
-
you need from that agent.
|
|
1185
|
-
`;
|
|
1186
|
-
|
|
1187
|
-
// src/agents/adapters.ts
|
|
1188
|
-
var fetchWithContextCall = async (context, ...params) => {
|
|
1189
|
-
const [input, init] = params;
|
|
1190
|
-
try {
|
|
1191
|
-
const headers = init?.headers ? Object.fromEntries(new Headers(init.headers).entries()) : {};
|
|
1192
|
-
const body = init?.body ? JSON.parse(init.body) : void 0;
|
|
1193
|
-
const agentName = headers[AGENT_NAME_HEADER];
|
|
1194
|
-
const stepName = agentName ? `Call Agent ${agentName}` : "Call Agent";
|
|
1195
|
-
const responseInfo = await context.call(stepName, {
|
|
1196
|
-
url: input.toString(),
|
|
1197
|
-
method: init?.method,
|
|
1198
|
-
headers,
|
|
1199
|
-
body
|
|
1200
|
-
});
|
|
1201
|
-
const responseHeaders = new Headers(
|
|
1202
|
-
Object.entries(responseInfo.header).reduce(
|
|
1203
|
-
(acc, [key, values]) => {
|
|
1204
|
-
acc[key] = values.join(", ");
|
|
1205
|
-
return acc;
|
|
1206
|
-
},
|
|
1207
|
-
{}
|
|
1208
|
-
)
|
|
1209
|
-
);
|
|
1210
|
-
return new Response(JSON.stringify(responseInfo.body), {
|
|
1211
|
-
status: responseInfo.status,
|
|
1212
|
-
headers: responseHeaders
|
|
1213
|
-
});
|
|
1214
|
-
} catch (error) {
|
|
1215
|
-
if (error instanceof Error && error.name === "WorkflowAbort") {
|
|
1216
|
-
throw error;
|
|
1217
|
-
} else {
|
|
1218
|
-
console.error("Error in fetch implementation:", error);
|
|
1219
|
-
throw error;
|
|
1220
|
-
}
|
|
1221
|
-
}
|
|
1222
|
-
};
|
|
1223
|
-
var createWorkflowModel = ({
|
|
1224
|
-
context,
|
|
1225
|
-
provider,
|
|
1226
|
-
providerParams
|
|
1227
|
-
}) => {
|
|
1228
|
-
return provider({
|
|
1229
|
-
fetch: (...params) => fetchWithContextCall(context, ...params),
|
|
1230
|
-
...providerParams
|
|
1231
|
-
});
|
|
1232
|
-
};
|
|
1233
|
-
var wrapTools = ({
|
|
1234
|
-
context,
|
|
1235
|
-
tools
|
|
1236
|
-
}) => {
|
|
1237
|
-
return Object.fromEntries(
|
|
1238
|
-
Object.entries(tools).map((toolInfo) => {
|
|
1239
|
-
const [toolName, tool3] = toolInfo;
|
|
1240
|
-
const executeAsStep = "executeAsStep" in tool3 ? tool3.executeAsStep : true;
|
|
1241
|
-
const aiSDKTool = convertToAISDKTool(tool3);
|
|
1242
|
-
const execute = aiSDKTool.execute;
|
|
1243
|
-
if (execute && executeAsStep) {
|
|
1244
|
-
const wrappedExecute = (...params) => {
|
|
1245
|
-
return context.run(`Run tool ${toolName}`, () => execute(...params));
|
|
1246
|
-
};
|
|
1247
|
-
aiSDKTool.execute = wrappedExecute;
|
|
1248
|
-
}
|
|
1249
|
-
return [toolName, aiSDKTool];
|
|
1250
|
-
})
|
|
1251
|
-
);
|
|
1252
|
-
};
|
|
1253
|
-
var convertToAISDKTool = (tool3) => {
|
|
1254
|
-
const isLangchainTool = "invoke" in tool3;
|
|
1255
|
-
return isLangchainTool ? convertLangchainTool(tool3) : tool3;
|
|
1256
|
-
};
|
|
1257
|
-
var convertLangchainTool = (langchainTool) => {
|
|
1258
|
-
return tool({
|
|
1259
|
-
description: langchainTool.description,
|
|
1260
|
-
parameters: langchainTool.schema,
|
|
1261
|
-
execute: async (...param) => langchainTool.invoke(...param)
|
|
1262
|
-
});
|
|
1263
|
-
};
|
|
1264
|
-
var WorkflowTool = class {
|
|
1265
|
-
/**
|
|
1266
|
-
* description of the tool
|
|
1267
|
-
*/
|
|
1268
|
-
description;
|
|
1269
|
-
/**
|
|
1270
|
-
* schema of the tool
|
|
1271
|
-
*/
|
|
1272
|
-
schema;
|
|
1273
|
-
/**
|
|
1274
|
-
* function to invoke the tool
|
|
1275
|
-
*/
|
|
1276
|
-
invoke;
|
|
1277
|
-
/**
|
|
1278
|
-
* whether the invoke method of the tool is to be wrapped with `context.run`
|
|
1279
|
-
*/
|
|
1280
|
-
executeAsStep;
|
|
1281
|
-
/**
|
|
1282
|
-
*
|
|
1283
|
-
* @param description description of the tool
|
|
1284
|
-
* @param schema schema of the tool
|
|
1285
|
-
* @param invoke function to invoke the tool
|
|
1286
|
-
* @param executeAsStep whether the invoke method of the tool is to be wrapped with `context.run`
|
|
1287
|
-
*/
|
|
1288
|
-
constructor(params) {
|
|
1289
|
-
this.description = params.description;
|
|
1290
|
-
this.schema = params.schema;
|
|
1291
|
-
this.invoke = params.invoke;
|
|
1292
|
-
this.executeAsStep = params.executeAsStep ?? true;
|
|
1089
|
+
|
|
1090
|
+
If signature is missing, trigger the workflow endpoint by publishing your request to QStash instead of calling it directly.
|
|
1091
|
+
|
|
1092
|
+
If you want to disable QStash Verification, you should clear env variables QSTASH_CURRENT_SIGNING_KEY and QSTASH_NEXT_SIGNING_KEY`
|
|
1093
|
+
);
|
|
1293
1094
|
}
|
|
1294
1095
|
};
|
|
1295
1096
|
|
|
@@ -1302,6 +1103,11 @@ var BaseLazyStep = class _BaseLazyStep {
|
|
|
1302
1103
|
"A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
|
|
1303
1104
|
);
|
|
1304
1105
|
}
|
|
1106
|
+
if (typeof stepName !== "string") {
|
|
1107
|
+
console.warn(
|
|
1108
|
+
"Workflow Warning: A workflow step name must be a string. In a future release, this will throw an error."
|
|
1109
|
+
);
|
|
1110
|
+
}
|
|
1305
1111
|
this.stepName = stepName;
|
|
1306
1112
|
}
|
|
1307
1113
|
/**
|
|
@@ -1351,6 +1157,40 @@ var BaseLazyStep = class _BaseLazyStep {
|
|
|
1351
1157
|
return stepOut;
|
|
1352
1158
|
}
|
|
1353
1159
|
}
|
|
1160
|
+
getBody({ step }) {
|
|
1161
|
+
step.out = JSON.stringify(step.out);
|
|
1162
|
+
return JSON.stringify(step);
|
|
1163
|
+
}
|
|
1164
|
+
getHeaders({ context, telemetry, invokeCount, step }) {
|
|
1165
|
+
return getHeaders({
|
|
1166
|
+
initHeaderValue: "false",
|
|
1167
|
+
workflowConfig: {
|
|
1168
|
+
workflowRunId: context.workflowRunId,
|
|
1169
|
+
workflowUrl: context.url,
|
|
1170
|
+
failureUrl: context.failureUrl,
|
|
1171
|
+
retries: context.retries,
|
|
1172
|
+
useJSONContent: false,
|
|
1173
|
+
telemetry,
|
|
1174
|
+
flowControl: context.flowControl
|
|
1175
|
+
},
|
|
1176
|
+
userHeaders: context.headers,
|
|
1177
|
+
invokeCount,
|
|
1178
|
+
stepInfo: {
|
|
1179
|
+
step,
|
|
1180
|
+
lazyStep: this
|
|
1181
|
+
}
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
async submitStep({ context, body, headers }) {
|
|
1185
|
+
return await context.qstashClient.batch([
|
|
1186
|
+
{
|
|
1187
|
+
body,
|
|
1188
|
+
headers,
|
|
1189
|
+
method: "POST",
|
|
1190
|
+
url: context.url
|
|
1191
|
+
}
|
|
1192
|
+
]);
|
|
1193
|
+
}
|
|
1354
1194
|
};
|
|
1355
1195
|
var LazyFunctionStep = class extends BaseLazyStep {
|
|
1356
1196
|
stepFunction;
|
|
@@ -1410,6 +1250,17 @@ var LazySleepStep = class extends BaseLazyStep {
|
|
|
1410
1250
|
concurrent
|
|
1411
1251
|
});
|
|
1412
1252
|
}
|
|
1253
|
+
async submitStep({ context, body, headers, isParallel }) {
|
|
1254
|
+
return await context.qstashClient.batch([
|
|
1255
|
+
{
|
|
1256
|
+
body,
|
|
1257
|
+
headers,
|
|
1258
|
+
method: "POST",
|
|
1259
|
+
url: context.url,
|
|
1260
|
+
delay: isParallel ? void 0 : this.sleep
|
|
1261
|
+
}
|
|
1262
|
+
]);
|
|
1263
|
+
}
|
|
1413
1264
|
};
|
|
1414
1265
|
var LazySleepUntilStep = class extends BaseLazyStep {
|
|
1415
1266
|
sleepUntil;
|
|
@@ -1441,6 +1292,17 @@ var LazySleepUntilStep = class extends BaseLazyStep {
|
|
|
1441
1292
|
safeParseOut() {
|
|
1442
1293
|
return void 0;
|
|
1443
1294
|
}
|
|
1295
|
+
async submitStep({ context, body, headers, isParallel }) {
|
|
1296
|
+
return await context.qstashClient.batch([
|
|
1297
|
+
{
|
|
1298
|
+
body,
|
|
1299
|
+
headers,
|
|
1300
|
+
method: "POST",
|
|
1301
|
+
url: context.url,
|
|
1302
|
+
notBefore: isParallel ? void 0 : this.sleepUntil
|
|
1303
|
+
}
|
|
1304
|
+
]);
|
|
1305
|
+
}
|
|
1444
1306
|
};
|
|
1445
1307
|
var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
|
|
1446
1308
|
url;
|
|
@@ -1502,7 +1364,7 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
|
|
|
1502
1364
|
return { header, status, body };
|
|
1503
1365
|
}
|
|
1504
1366
|
}
|
|
1505
|
-
static
|
|
1367
|
+
static applicationContentTypes = [
|
|
1506
1368
|
"application/json",
|
|
1507
1369
|
"application/xml",
|
|
1508
1370
|
"application/javascript",
|
|
@@ -1511,12 +1373,12 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
|
|
|
1511
1373
|
"application/ld+json",
|
|
1512
1374
|
"application/rss+xml",
|
|
1513
1375
|
"application/atom+xml"
|
|
1514
|
-
]
|
|
1376
|
+
];
|
|
1515
1377
|
static isText = (contentTypeHeader) => {
|
|
1516
1378
|
if (!contentTypeHeader) {
|
|
1517
1379
|
return false;
|
|
1518
1380
|
}
|
|
1519
|
-
if (_LazyCallStep.
|
|
1381
|
+
if (_LazyCallStep.applicationContentTypes.some((type) => contentTypeHeader.includes(type))) {
|
|
1520
1382
|
return true;
|
|
1521
1383
|
}
|
|
1522
1384
|
if (contentTypeHeader.startsWith("text/")) {
|
|
@@ -1524,6 +1386,58 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
|
|
|
1524
1386
|
}
|
|
1525
1387
|
return false;
|
|
1526
1388
|
};
|
|
1389
|
+
getBody({ step }) {
|
|
1390
|
+
if (!step.callUrl) {
|
|
1391
|
+
throw new WorkflowError("Incompatible step received in LazyCallStep.getBody");
|
|
1392
|
+
}
|
|
1393
|
+
return JSON.stringify(step.callBody);
|
|
1394
|
+
}
|
|
1395
|
+
getHeaders({ context, telemetry, invokeCount, step }) {
|
|
1396
|
+
const { headers, contentType } = super.getHeaders({ context, telemetry, invokeCount, step });
|
|
1397
|
+
headers["Upstash-Retries"] = this.retries.toString();
|
|
1398
|
+
headers[WORKFLOW_FEATURE_HEADER] = "WF_NoDelete,InitialBody";
|
|
1399
|
+
if (this.flowControl) {
|
|
1400
|
+
const { flowControlKey, flowControlValue } = prepareFlowControl(this.flowControl);
|
|
1401
|
+
headers["Upstash-Flow-Control-Key"] = flowControlKey;
|
|
1402
|
+
headers["Upstash-Flow-Control-Value"] = flowControlValue;
|
|
1403
|
+
}
|
|
1404
|
+
if (this.timeout) {
|
|
1405
|
+
headers["Upstash-Timeout"] = this.timeout.toString();
|
|
1406
|
+
}
|
|
1407
|
+
const forwardedHeaders = Object.fromEntries(
|
|
1408
|
+
Object.entries(this.headers).map(([header, value]) => [`Upstash-Forward-${header}`, value])
|
|
1409
|
+
);
|
|
1410
|
+
return {
|
|
1411
|
+
headers: {
|
|
1412
|
+
...headers,
|
|
1413
|
+
...forwardedHeaders,
|
|
1414
|
+
"Upstash-Callback": context.url,
|
|
1415
|
+
"Upstash-Callback-Workflow-RunId": context.workflowRunId,
|
|
1416
|
+
"Upstash-Callback-Workflow-CallType": "fromCallback",
|
|
1417
|
+
"Upstash-Callback-Workflow-Init": "false",
|
|
1418
|
+
"Upstash-Callback-Workflow-Url": context.url,
|
|
1419
|
+
"Upstash-Callback-Feature-Set": "LazyFetch,InitialBody",
|
|
1420
|
+
"Upstash-Callback-Forward-Upstash-Workflow-Callback": "true",
|
|
1421
|
+
"Upstash-Callback-Forward-Upstash-Workflow-StepId": step.stepId.toString(),
|
|
1422
|
+
"Upstash-Callback-Forward-Upstash-Workflow-StepName": this.stepName,
|
|
1423
|
+
"Upstash-Callback-Forward-Upstash-Workflow-StepType": this.stepType,
|
|
1424
|
+
"Upstash-Callback-Forward-Upstash-Workflow-Concurrent": step.concurrent.toString(),
|
|
1425
|
+
"Upstash-Callback-Forward-Upstash-Workflow-ContentType": contentType,
|
|
1426
|
+
"Upstash-Workflow-CallType": "toCallback"
|
|
1427
|
+
},
|
|
1428
|
+
contentType
|
|
1429
|
+
};
|
|
1430
|
+
}
|
|
1431
|
+
async submitStep({ context, headers }) {
|
|
1432
|
+
return await context.qstashClient.batch([
|
|
1433
|
+
{
|
|
1434
|
+
headers,
|
|
1435
|
+
body: JSON.stringify(this.body),
|
|
1436
|
+
method: this.method,
|
|
1437
|
+
url: this.url
|
|
1438
|
+
}
|
|
1439
|
+
]);
|
|
1440
|
+
}
|
|
1527
1441
|
};
|
|
1528
1442
|
var LazyWaitForEventStep = class extends BaseLazyStep {
|
|
1529
1443
|
eventId;
|
|
@@ -1563,6 +1477,57 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
|
|
|
1563
1477
|
eventData: BaseLazyStep.tryParsing(result.eventData)
|
|
1564
1478
|
};
|
|
1565
1479
|
}
|
|
1480
|
+
getHeaders({ context, telemetry, invokeCount, step }) {
|
|
1481
|
+
const headers = super.getHeaders({ context, telemetry, invokeCount, step });
|
|
1482
|
+
headers.headers["Upstash-Workflow-CallType"] = "step";
|
|
1483
|
+
return headers;
|
|
1484
|
+
}
|
|
1485
|
+
getBody({ context, step, headers, telemetry }) {
|
|
1486
|
+
if (!step.waitEventId) {
|
|
1487
|
+
throw new WorkflowError("Incompatible step received in LazyWaitForEventStep.getBody");
|
|
1488
|
+
}
|
|
1489
|
+
const timeoutHeaders = {
|
|
1490
|
+
// to include user headers:
|
|
1491
|
+
...Object.fromEntries(Object.entries(headers).map(([header, value]) => [header, [value]])),
|
|
1492
|
+
// to include telemetry headers:
|
|
1493
|
+
...telemetry ? Object.fromEntries(
|
|
1494
|
+
Object.entries(getTelemetryHeaders(telemetry)).map(([header, value]) => [
|
|
1495
|
+
header,
|
|
1496
|
+
[value]
|
|
1497
|
+
])
|
|
1498
|
+
) : {},
|
|
1499
|
+
// note: using WORKFLOW_ID_HEADER doesn't work, because Runid -> RunId:
|
|
1500
|
+
"Upstash-Workflow-Runid": [context.workflowRunId],
|
|
1501
|
+
[WORKFLOW_INIT_HEADER]: ["false"],
|
|
1502
|
+
[WORKFLOW_URL_HEADER]: [context.url],
|
|
1503
|
+
"Upstash-Workflow-CallType": ["step"]
|
|
1504
|
+
};
|
|
1505
|
+
const waitBody = {
|
|
1506
|
+
url: context.url,
|
|
1507
|
+
timeout: step.timeout,
|
|
1508
|
+
timeoutBody: void 0,
|
|
1509
|
+
timeoutUrl: context.url,
|
|
1510
|
+
timeoutHeaders,
|
|
1511
|
+
step: {
|
|
1512
|
+
stepId: step.stepId,
|
|
1513
|
+
stepType: "Wait",
|
|
1514
|
+
stepName: step.stepName,
|
|
1515
|
+
concurrent: step.concurrent,
|
|
1516
|
+
targetStep: step.targetStep
|
|
1517
|
+
}
|
|
1518
|
+
};
|
|
1519
|
+
return JSON.stringify(waitBody);
|
|
1520
|
+
}
|
|
1521
|
+
async submitStep({ context, body, headers }) {
|
|
1522
|
+
const result = await context.qstashClient.http.request({
|
|
1523
|
+
path: ["v2", "wait", this.eventId],
|
|
1524
|
+
body,
|
|
1525
|
+
headers,
|
|
1526
|
+
method: "POST",
|
|
1527
|
+
parseResponseAsJson: false
|
|
1528
|
+
});
|
|
1529
|
+
return [result];
|
|
1530
|
+
}
|
|
1566
1531
|
};
|
|
1567
1532
|
var LazyNotifyStep = class extends LazyFunctionStep {
|
|
1568
1533
|
stepType = "Notify";
|
|
@@ -1588,6 +1553,10 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1588
1553
|
stepType = "Invoke";
|
|
1589
1554
|
params;
|
|
1590
1555
|
allowUndefinedOut = false;
|
|
1556
|
+
/**
|
|
1557
|
+
* workflow id of the invoked workflow
|
|
1558
|
+
*/
|
|
1559
|
+
workflowId;
|
|
1591
1560
|
constructor(stepName, {
|
|
1592
1561
|
workflow,
|
|
1593
1562
|
body,
|
|
@@ -1605,6 +1574,11 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1605
1574
|
retries,
|
|
1606
1575
|
flowControl
|
|
1607
1576
|
};
|
|
1577
|
+
const { workflowId } = workflow;
|
|
1578
|
+
if (!workflowId) {
|
|
1579
|
+
throw new WorkflowError("You can only invoke workflow which has a workflowId");
|
|
1580
|
+
}
|
|
1581
|
+
this.workflowId = workflowId;
|
|
1608
1582
|
}
|
|
1609
1583
|
getPlanStep(concurrent, targetStep) {
|
|
1610
1584
|
return {
|
|
@@ -1634,10 +1608,348 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1634
1608
|
body: BaseLazyStep.tryParsing(result.body)
|
|
1635
1609
|
};
|
|
1636
1610
|
}
|
|
1611
|
+
getBody({ context, step, telemetry, invokeCount }) {
|
|
1612
|
+
const { headers: invokerHeaders } = getHeaders({
|
|
1613
|
+
initHeaderValue: "false",
|
|
1614
|
+
workflowConfig: {
|
|
1615
|
+
workflowRunId: context.workflowRunId,
|
|
1616
|
+
workflowUrl: context.url,
|
|
1617
|
+
failureUrl: context.failureUrl,
|
|
1618
|
+
retries: context.retries,
|
|
1619
|
+
telemetry,
|
|
1620
|
+
flowControl: context.flowControl,
|
|
1621
|
+
useJSONContent: false
|
|
1622
|
+
},
|
|
1623
|
+
userHeaders: context.headers,
|
|
1624
|
+
invokeCount
|
|
1625
|
+
});
|
|
1626
|
+
invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
|
|
1627
|
+
const request = {
|
|
1628
|
+
body: JSON.stringify(this.params.body),
|
|
1629
|
+
headers: Object.fromEntries(
|
|
1630
|
+
Object.entries(invokerHeaders).map((pairs) => [pairs[0], [pairs[1]]])
|
|
1631
|
+
),
|
|
1632
|
+
workflowRunId: context.workflowRunId,
|
|
1633
|
+
workflowUrl: context.url,
|
|
1634
|
+
step
|
|
1635
|
+
};
|
|
1636
|
+
return JSON.stringify(request);
|
|
1637
|
+
}
|
|
1638
|
+
getHeaders({ context, telemetry, invokeCount }) {
|
|
1639
|
+
const {
|
|
1640
|
+
workflow,
|
|
1641
|
+
headers = {},
|
|
1642
|
+
workflowRunId = getWorkflowRunId(),
|
|
1643
|
+
retries,
|
|
1644
|
+
flowControl
|
|
1645
|
+
} = this.params;
|
|
1646
|
+
const newUrl = context.url.replace(/[^/]+$/, this.workflowId);
|
|
1647
|
+
const {
|
|
1648
|
+
retries: workflowRetries,
|
|
1649
|
+
failureFunction,
|
|
1650
|
+
failureUrl,
|
|
1651
|
+
useJSONContent,
|
|
1652
|
+
flowControl: workflowFlowControl
|
|
1653
|
+
} = workflow.options;
|
|
1654
|
+
const { headers: triggerHeaders, contentType } = getHeaders({
|
|
1655
|
+
initHeaderValue: "true",
|
|
1656
|
+
workflowConfig: {
|
|
1657
|
+
workflowRunId,
|
|
1658
|
+
workflowUrl: newUrl,
|
|
1659
|
+
retries: retries ?? workflowRetries,
|
|
1660
|
+
telemetry,
|
|
1661
|
+
failureUrl: failureFunction ? newUrl : failureUrl,
|
|
1662
|
+
flowControl: flowControl ?? workflowFlowControl,
|
|
1663
|
+
useJSONContent: useJSONContent ?? false
|
|
1664
|
+
},
|
|
1665
|
+
invokeCount: invokeCount + 1,
|
|
1666
|
+
userHeaders: new Headers(headers)
|
|
1667
|
+
});
|
|
1668
|
+
triggerHeaders["Upstash-Workflow-Invoke"] = "true";
|
|
1669
|
+
return { headers: triggerHeaders, contentType };
|
|
1670
|
+
}
|
|
1671
|
+
async submitStep({ context, body, headers }) {
|
|
1672
|
+
const newUrl = context.url.replace(/[^/]+$/, this.workflowId);
|
|
1673
|
+
const result = await context.qstashClient.publish({
|
|
1674
|
+
headers,
|
|
1675
|
+
method: "POST",
|
|
1676
|
+
body,
|
|
1677
|
+
url: newUrl
|
|
1678
|
+
});
|
|
1679
|
+
return [result];
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
|
|
1683
|
+
// src/qstash/headers.ts
|
|
1684
|
+
var WorkflowHeaders = class {
|
|
1685
|
+
userHeaders;
|
|
1686
|
+
workflowConfig;
|
|
1687
|
+
invokeCount;
|
|
1688
|
+
initHeaderValue;
|
|
1689
|
+
stepInfo;
|
|
1690
|
+
headers;
|
|
1691
|
+
constructor({
|
|
1692
|
+
userHeaders,
|
|
1693
|
+
workflowConfig,
|
|
1694
|
+
invokeCount,
|
|
1695
|
+
initHeaderValue,
|
|
1696
|
+
stepInfo
|
|
1697
|
+
}) {
|
|
1698
|
+
this.userHeaders = userHeaders;
|
|
1699
|
+
this.workflowConfig = workflowConfig;
|
|
1700
|
+
this.invokeCount = invokeCount;
|
|
1701
|
+
this.initHeaderValue = initHeaderValue;
|
|
1702
|
+
this.stepInfo = stepInfo;
|
|
1703
|
+
this.headers = {
|
|
1704
|
+
rawHeaders: {},
|
|
1705
|
+
workflowHeaders: {},
|
|
1706
|
+
failureHeaders: {}
|
|
1707
|
+
};
|
|
1708
|
+
}
|
|
1709
|
+
getHeaders() {
|
|
1710
|
+
this.addBaseHeaders();
|
|
1711
|
+
this.addRetries();
|
|
1712
|
+
this.addFlowControl();
|
|
1713
|
+
this.addUserHeaders();
|
|
1714
|
+
this.addInvokeCount();
|
|
1715
|
+
this.addFailureUrl();
|
|
1716
|
+
const contentType = this.addContentType();
|
|
1717
|
+
return this.prefixHeaders(contentType);
|
|
1718
|
+
}
|
|
1719
|
+
addBaseHeaders() {
|
|
1720
|
+
this.headers.rawHeaders = {
|
|
1721
|
+
...this.headers.rawHeaders,
|
|
1722
|
+
[WORKFLOW_INIT_HEADER]: this.initHeaderValue,
|
|
1723
|
+
[WORKFLOW_ID_HEADER]: this.workflowConfig.workflowRunId,
|
|
1724
|
+
[WORKFLOW_URL_HEADER]: this.workflowConfig.workflowUrl,
|
|
1725
|
+
[WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody",
|
|
1726
|
+
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
|
|
1727
|
+
...this.workflowConfig.telemetry ? getTelemetryHeaders(this.workflowConfig.telemetry) : {},
|
|
1728
|
+
...this.workflowConfig.telemetry && this.stepInfo?.lazyStep instanceof LazyCallStep && this.stepInfo.lazyStep.headers[AGENT_NAME_HEADER] ? { [TELEMETRY_HEADER_AGENT]: "true" } : {}
|
|
1729
|
+
};
|
|
1730
|
+
if (this.stepInfo?.lazyStep.stepType !== "Call") {
|
|
1731
|
+
this.headers.rawHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
addInvokeCount() {
|
|
1735
|
+
if (this.invokeCount === void 0 || this.invokeCount === 0) {
|
|
1736
|
+
return;
|
|
1737
|
+
}
|
|
1738
|
+
const invokeCount = this.invokeCount.toString();
|
|
1739
|
+
this.headers.workflowHeaders[`Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`] = invokeCount;
|
|
1740
|
+
if (this.workflowConfig.failureUrl) {
|
|
1741
|
+
this.headers.failureHeaders[`Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`] = invokeCount;
|
|
1742
|
+
}
|
|
1743
|
+
if (this.stepInfo?.lazyStep instanceof LazyCallStep) {
|
|
1744
|
+
this.headers.rawHeaders[`Upstash-Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`] = invokeCount;
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
addRetries() {
|
|
1748
|
+
if (this.workflowConfig.retries === void 0 || this.workflowConfig.retries === DEFAULT_RETRIES) {
|
|
1749
|
+
return;
|
|
1750
|
+
}
|
|
1751
|
+
const retries = this.workflowConfig.retries.toString();
|
|
1752
|
+
this.headers.workflowHeaders["Retries"] = retries;
|
|
1753
|
+
if (this.workflowConfig.failureUrl) {
|
|
1754
|
+
this.headers.failureHeaders["Retries"] = retries;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
addFlowControl() {
|
|
1758
|
+
if (!this.workflowConfig.flowControl) {
|
|
1759
|
+
return;
|
|
1760
|
+
}
|
|
1761
|
+
const { flowControlKey, flowControlValue } = prepareFlowControl(
|
|
1762
|
+
this.workflowConfig.flowControl
|
|
1763
|
+
);
|
|
1764
|
+
this.headers.workflowHeaders["Flow-Control-Key"] = flowControlKey;
|
|
1765
|
+
this.headers.workflowHeaders["Flow-Control-Value"] = flowControlValue;
|
|
1766
|
+
if (this.workflowConfig.failureUrl) {
|
|
1767
|
+
this.headers.failureHeaders["Flow-Control-Key"] = flowControlKey;
|
|
1768
|
+
this.headers.failureHeaders["Flow-Control-Value"] = flowControlValue;
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
addUserHeaders() {
|
|
1772
|
+
for (const [key, value] of this.userHeaders.entries()) {
|
|
1773
|
+
const forwardKey = `Forward-${key}`;
|
|
1774
|
+
this.headers.workflowHeaders[forwardKey] = value;
|
|
1775
|
+
if (this.workflowConfig.failureUrl) {
|
|
1776
|
+
this.headers.failureHeaders[forwardKey] = value;
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
addFailureUrl() {
|
|
1781
|
+
if (!this.workflowConfig.failureUrl) {
|
|
1782
|
+
return;
|
|
1783
|
+
}
|
|
1784
|
+
this.headers.workflowHeaders["Failure-Callback"] = this.workflowConfig.failureUrl;
|
|
1785
|
+
this.headers.failureHeaders[`Forward-${WORKFLOW_FAILURE_HEADER}`] = "true";
|
|
1786
|
+
this.headers.failureHeaders[`Forward-Upstash-Workflow-Failure-Callback`] = "true";
|
|
1787
|
+
this.headers.failureHeaders["Workflow-Runid"] = this.workflowConfig.workflowRunId;
|
|
1788
|
+
this.headers.failureHeaders["Workflow-Init"] = "false";
|
|
1789
|
+
this.headers.failureHeaders["Workflow-Url"] = this.workflowConfig.workflowUrl;
|
|
1790
|
+
this.headers.failureHeaders["Workflow-Calltype"] = "failureCall";
|
|
1791
|
+
this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody";
|
|
1792
|
+
if (this.workflowConfig.retries !== void 0 && this.workflowConfig.retries !== DEFAULT_RETRIES) {
|
|
1793
|
+
this.headers.failureHeaders["Retries"] = this.workflowConfig.retries.toString();
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
addContentType() {
|
|
1797
|
+
if (this.workflowConfig.useJSONContent) {
|
|
1798
|
+
this.headers.rawHeaders["content-type"] = "application/json";
|
|
1799
|
+
return "application/json";
|
|
1800
|
+
}
|
|
1801
|
+
const callHeaders = new Headers(
|
|
1802
|
+
this.stepInfo?.lazyStep instanceof LazyCallStep ? this.stepInfo.lazyStep.headers : {}
|
|
1803
|
+
);
|
|
1804
|
+
const contentType = (callHeaders.get("content-type") ? callHeaders.get("content-type") : this.userHeaders?.get("Content-Type") ? this.userHeaders.get("Content-Type") : void 0) ?? DEFAULT_CONTENT_TYPE;
|
|
1805
|
+
this.headers.rawHeaders["content-type"] = contentType;
|
|
1806
|
+
return contentType;
|
|
1807
|
+
}
|
|
1808
|
+
prefixHeaders(contentType) {
|
|
1809
|
+
const { rawHeaders, workflowHeaders, failureHeaders } = this.headers;
|
|
1810
|
+
const isCall = this.stepInfo?.lazyStep.stepType === "Call";
|
|
1811
|
+
return {
|
|
1812
|
+
headers: {
|
|
1813
|
+
...rawHeaders,
|
|
1814
|
+
...addPrefixToHeaders(workflowHeaders, isCall ? "Upstash-Callback-" : "Upstash-"),
|
|
1815
|
+
...addPrefixToHeaders(failureHeaders, "Upstash-Failure-Callback-"),
|
|
1816
|
+
...isCall ? addPrefixToHeaders(failureHeaders, "Upstash-Callback-Failure-Callback-") : {}
|
|
1817
|
+
},
|
|
1818
|
+
contentType
|
|
1819
|
+
};
|
|
1820
|
+
}
|
|
1821
|
+
};
|
|
1822
|
+
function addPrefixToHeaders(headers, prefix) {
|
|
1823
|
+
const prefixedHeaders = {};
|
|
1824
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
1825
|
+
prefixedHeaders[`${prefix}${key}`] = value;
|
|
1826
|
+
}
|
|
1827
|
+
return prefixedHeaders;
|
|
1828
|
+
}
|
|
1829
|
+
var prepareFlowControl = (flowControl) => {
|
|
1830
|
+
const parallelism = flowControl.parallelism?.toString();
|
|
1831
|
+
const rate = (flowControl.rate ?? flowControl.ratePerSecond)?.toString();
|
|
1832
|
+
const period = typeof flowControl.period === "number" ? `${flowControl.period}s` : flowControl.period;
|
|
1833
|
+
const controlValue = [
|
|
1834
|
+
parallelism ? `parallelism=${parallelism}` : void 0,
|
|
1835
|
+
rate ? `rate=${rate}` : void 0,
|
|
1836
|
+
period ? `period=${period}` : void 0
|
|
1837
|
+
].filter(Boolean);
|
|
1838
|
+
if (controlValue.length === 0) {
|
|
1839
|
+
throw new QstashError4("Provide at least one of parallelism or ratePerSecond for flowControl");
|
|
1840
|
+
}
|
|
1841
|
+
return {
|
|
1842
|
+
flowControlKey: flowControl.key,
|
|
1843
|
+
flowControlValue: controlValue.join(", ")
|
|
1844
|
+
};
|
|
1845
|
+
};
|
|
1846
|
+
var getHeaders = (params) => {
|
|
1847
|
+
const workflowHeaders = new WorkflowHeaders(params);
|
|
1848
|
+
return workflowHeaders.getHeaders();
|
|
1849
|
+
};
|
|
1850
|
+
|
|
1851
|
+
// src/qstash/submit-steps.ts
|
|
1852
|
+
var submitParallelSteps = async ({
|
|
1853
|
+
context,
|
|
1854
|
+
steps,
|
|
1855
|
+
initialStepCount,
|
|
1856
|
+
invokeCount,
|
|
1857
|
+
telemetry,
|
|
1858
|
+
debug
|
|
1859
|
+
}) => {
|
|
1860
|
+
const planSteps = steps.map(
|
|
1861
|
+
(step, index) => step.getPlanStep(steps.length, initialStepCount + index)
|
|
1862
|
+
);
|
|
1863
|
+
await debug?.log("SUBMIT", "SUBMIT_STEP", {
|
|
1864
|
+
length: planSteps.length,
|
|
1865
|
+
steps: planSteps
|
|
1866
|
+
});
|
|
1867
|
+
const result = await context.qstashClient.batch(
|
|
1868
|
+
planSteps.map((planStep) => {
|
|
1869
|
+
const { headers } = getHeaders({
|
|
1870
|
+
initHeaderValue: "false",
|
|
1871
|
+
workflowConfig: {
|
|
1872
|
+
workflowRunId: context.workflowRunId,
|
|
1873
|
+
workflowUrl: context.url,
|
|
1874
|
+
failureUrl: context.failureUrl,
|
|
1875
|
+
retries: context.retries,
|
|
1876
|
+
flowControl: context.flowControl,
|
|
1877
|
+
telemetry
|
|
1878
|
+
},
|
|
1879
|
+
userHeaders: context.headers,
|
|
1880
|
+
invokeCount
|
|
1881
|
+
});
|
|
1882
|
+
return {
|
|
1883
|
+
headers,
|
|
1884
|
+
method: "POST",
|
|
1885
|
+
url: context.url,
|
|
1886
|
+
body: JSON.stringify(planStep),
|
|
1887
|
+
notBefore: planStep.sleepUntil,
|
|
1888
|
+
delay: planStep.sleepFor
|
|
1889
|
+
};
|
|
1890
|
+
})
|
|
1891
|
+
);
|
|
1892
|
+
await debug?.log("INFO", "SUBMIT_STEP", {
|
|
1893
|
+
messageIds: result.map((message) => {
|
|
1894
|
+
return {
|
|
1895
|
+
message: message.messageId
|
|
1896
|
+
};
|
|
1897
|
+
})
|
|
1898
|
+
});
|
|
1899
|
+
throw new WorkflowAbort(planSteps[0].stepName, planSteps[0]);
|
|
1900
|
+
};
|
|
1901
|
+
var submitSingleStep = async ({
|
|
1902
|
+
context,
|
|
1903
|
+
lazyStep,
|
|
1904
|
+
stepId,
|
|
1905
|
+
invokeCount,
|
|
1906
|
+
concurrency,
|
|
1907
|
+
telemetry,
|
|
1908
|
+
debug
|
|
1909
|
+
}) => {
|
|
1910
|
+
const resultStep = await lazyStep.getResultStep(concurrency, stepId);
|
|
1911
|
+
await debug?.log("INFO", "RUN_SINGLE", {
|
|
1912
|
+
fromRequest: false,
|
|
1913
|
+
step: resultStep,
|
|
1914
|
+
stepCount: stepId
|
|
1915
|
+
});
|
|
1916
|
+
const { headers } = lazyStep.getHeaders({
|
|
1917
|
+
context,
|
|
1918
|
+
step: resultStep,
|
|
1919
|
+
invokeCount,
|
|
1920
|
+
telemetry
|
|
1921
|
+
});
|
|
1922
|
+
const body = lazyStep.getBody({
|
|
1923
|
+
context,
|
|
1924
|
+
step: resultStep,
|
|
1925
|
+
headers,
|
|
1926
|
+
invokeCount,
|
|
1927
|
+
telemetry
|
|
1928
|
+
});
|
|
1929
|
+
await debug?.log("SUBMIT", "SUBMIT_STEP", {
|
|
1930
|
+
length: 1,
|
|
1931
|
+
steps: [resultStep]
|
|
1932
|
+
});
|
|
1933
|
+
const submitResult = await lazyStep.submitStep({
|
|
1934
|
+
context,
|
|
1935
|
+
body,
|
|
1936
|
+
headers,
|
|
1937
|
+
isParallel: concurrency !== NO_CONCURRENCY,
|
|
1938
|
+
invokeCount,
|
|
1939
|
+
step: resultStep,
|
|
1940
|
+
telemetry
|
|
1941
|
+
});
|
|
1942
|
+
await debug?.log("INFO", "SUBMIT_STEP", {
|
|
1943
|
+
messageIds: submitResult.map((message) => {
|
|
1944
|
+
return {
|
|
1945
|
+
message: message.messageId
|
|
1946
|
+
};
|
|
1947
|
+
})
|
|
1948
|
+
});
|
|
1949
|
+
return resultStep;
|
|
1637
1950
|
};
|
|
1638
1951
|
|
|
1639
1952
|
// src/context/auto-executor.ts
|
|
1640
|
-
import { QstashError as QstashError4 } from "@upstash/qstash";
|
|
1641
1953
|
var AutoExecutor = class _AutoExecutor {
|
|
1642
1954
|
context;
|
|
1643
1955
|
promises = /* @__PURE__ */ new WeakMap();
|
|
@@ -1741,14 +2053,16 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1741
2053
|
});
|
|
1742
2054
|
return lazyStep.parseOut(step.out);
|
|
1743
2055
|
}
|
|
1744
|
-
const resultStep = await
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
2056
|
+
const resultStep = await submitSingleStep({
|
|
2057
|
+
context: this.context,
|
|
2058
|
+
lazyStep,
|
|
2059
|
+
stepId: this.stepCount,
|
|
2060
|
+
invokeCount: this.invokeCount,
|
|
2061
|
+
concurrency: 1,
|
|
2062
|
+
telemetry: this.telemetry,
|
|
2063
|
+
debug: this.debug
|
|
1749
2064
|
});
|
|
1750
|
-
|
|
1751
|
-
return resultStep.out;
|
|
2065
|
+
throw new WorkflowAbort(lazyStep.stepName, resultStep);
|
|
1752
2066
|
}
|
|
1753
2067
|
/**
|
|
1754
2068
|
* Runs steps in parallel.
|
|
@@ -1776,10 +2090,14 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1776
2090
|
});
|
|
1777
2091
|
switch (parallelCallState) {
|
|
1778
2092
|
case "first": {
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
2093
|
+
await submitParallelSteps({
|
|
2094
|
+
context: this.context,
|
|
2095
|
+
steps: parallelSteps,
|
|
2096
|
+
initialStepCount,
|
|
2097
|
+
invokeCount: this.invokeCount,
|
|
2098
|
+
telemetry: this.telemetry,
|
|
2099
|
+
debug: this.debug
|
|
2100
|
+
});
|
|
1783
2101
|
break;
|
|
1784
2102
|
}
|
|
1785
2103
|
case "partial": {
|
|
@@ -1793,13 +2111,18 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1793
2111
|
validateStep(parallelSteps[stepIndex], planStep);
|
|
1794
2112
|
try {
|
|
1795
2113
|
const parallelStep = parallelSteps[stepIndex];
|
|
1796
|
-
const resultStep = await
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
2114
|
+
const resultStep = await submitSingleStep({
|
|
2115
|
+
context: this.context,
|
|
2116
|
+
lazyStep: parallelStep,
|
|
2117
|
+
stepId: planStep.targetStep,
|
|
2118
|
+
invokeCount: this.invokeCount,
|
|
2119
|
+
concurrency: parallelSteps.length,
|
|
2120
|
+
telemetry: this.telemetry,
|
|
2121
|
+
debug: this.debug
|
|
2122
|
+
});
|
|
2123
|
+
throw new WorkflowAbort(parallelStep.stepName, resultStep);
|
|
1801
2124
|
} catch (error) {
|
|
1802
|
-
if (error instanceof WorkflowAbort || error instanceof
|
|
2125
|
+
if (error instanceof WorkflowAbort || error instanceof QstashError5 && error.status === 400) {
|
|
1803
2126
|
throw error;
|
|
1804
2127
|
}
|
|
1805
2128
|
throw new WorkflowError(
|
|
@@ -1855,128 +2178,6 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1855
2178
|
return "discard";
|
|
1856
2179
|
}
|
|
1857
2180
|
}
|
|
1858
|
-
/**
|
|
1859
|
-
* sends the steps to QStash as batch
|
|
1860
|
-
*
|
|
1861
|
-
* @param steps steps to send
|
|
1862
|
-
*/
|
|
1863
|
-
async submitStepsToQStash(steps, lazySteps) {
|
|
1864
|
-
if (steps.length === 0) {
|
|
1865
|
-
throw new WorkflowError(
|
|
1866
|
-
`Unable to submit steps to QStash. Provided list is empty. Current step: ${this.stepCount}`
|
|
1867
|
-
);
|
|
1868
|
-
}
|
|
1869
|
-
await this.debug?.log("SUBMIT", "SUBMIT_STEP", {
|
|
1870
|
-
length: steps.length,
|
|
1871
|
-
steps
|
|
1872
|
-
});
|
|
1873
|
-
if (steps[0].waitEventId && steps.length === 1) {
|
|
1874
|
-
const waitStep = steps[0];
|
|
1875
|
-
const { headers, timeoutHeaders } = getHeaders({
|
|
1876
|
-
initHeaderValue: "false",
|
|
1877
|
-
workflowRunId: this.context.workflowRunId,
|
|
1878
|
-
workflowUrl: this.context.url,
|
|
1879
|
-
userHeaders: this.context.headers,
|
|
1880
|
-
step: waitStep,
|
|
1881
|
-
failureUrl: this.context.failureUrl,
|
|
1882
|
-
retries: this.context.retries,
|
|
1883
|
-
telemetry: this.telemetry,
|
|
1884
|
-
invokeCount: this.invokeCount,
|
|
1885
|
-
flowControl: this.context.flowControl
|
|
1886
|
-
});
|
|
1887
|
-
const waitBody = {
|
|
1888
|
-
url: this.context.url,
|
|
1889
|
-
timeout: waitStep.timeout,
|
|
1890
|
-
timeoutBody: void 0,
|
|
1891
|
-
timeoutUrl: this.context.url,
|
|
1892
|
-
timeoutHeaders,
|
|
1893
|
-
step: {
|
|
1894
|
-
stepId: waitStep.stepId,
|
|
1895
|
-
stepType: "Wait",
|
|
1896
|
-
stepName: waitStep.stepName,
|
|
1897
|
-
concurrent: waitStep.concurrent,
|
|
1898
|
-
targetStep: waitStep.targetStep
|
|
1899
|
-
}
|
|
1900
|
-
};
|
|
1901
|
-
await this.context.qstashClient.http.request({
|
|
1902
|
-
path: ["v2", "wait", waitStep.waitEventId],
|
|
1903
|
-
body: JSON.stringify(waitBody),
|
|
1904
|
-
headers,
|
|
1905
|
-
method: "POST",
|
|
1906
|
-
parseResponseAsJson: false
|
|
1907
|
-
});
|
|
1908
|
-
throw new WorkflowAbort(waitStep.stepName, waitStep);
|
|
1909
|
-
}
|
|
1910
|
-
if (steps.length === 1 && lazySteps[0] instanceof LazyInvokeStep) {
|
|
1911
|
-
const invokeStep = steps[0];
|
|
1912
|
-
const lazyInvokeStep = lazySteps[0];
|
|
1913
|
-
await invokeWorkflow({
|
|
1914
|
-
settings: lazyInvokeStep.params,
|
|
1915
|
-
invokeStep,
|
|
1916
|
-
context: this.context,
|
|
1917
|
-
invokeCount: this.invokeCount,
|
|
1918
|
-
telemetry: this.telemetry
|
|
1919
|
-
});
|
|
1920
|
-
throw new WorkflowAbort(invokeStep.stepName, invokeStep);
|
|
1921
|
-
}
|
|
1922
|
-
const result = await this.context.qstashClient.batch(
|
|
1923
|
-
steps.map((singleStep, index) => {
|
|
1924
|
-
const lazyStep = lazySteps[index];
|
|
1925
|
-
const { headers } = getHeaders({
|
|
1926
|
-
initHeaderValue: "false",
|
|
1927
|
-
workflowRunId: this.context.workflowRunId,
|
|
1928
|
-
workflowUrl: this.context.url,
|
|
1929
|
-
userHeaders: this.context.headers,
|
|
1930
|
-
step: singleStep,
|
|
1931
|
-
failureUrl: this.context.failureUrl,
|
|
1932
|
-
retries: this.context.retries,
|
|
1933
|
-
callRetries: lazyStep instanceof LazyCallStep ? lazyStep.retries : void 0,
|
|
1934
|
-
callTimeout: lazyStep instanceof LazyCallStep ? lazyStep.timeout : void 0,
|
|
1935
|
-
telemetry: this.telemetry,
|
|
1936
|
-
invokeCount: this.invokeCount,
|
|
1937
|
-
flowControl: this.context.flowControl,
|
|
1938
|
-
callFlowControl: lazyStep instanceof LazyCallStep ? lazyStep.flowControl : void 0
|
|
1939
|
-
});
|
|
1940
|
-
const willWait = singleStep.concurrent === NO_CONCURRENCY || singleStep.stepId === 0;
|
|
1941
|
-
singleStep.out = JSON.stringify(singleStep.out);
|
|
1942
|
-
return singleStep.callUrl && lazyStep instanceof LazyCallStep ? (
|
|
1943
|
-
// if the step is a third party call, we call the third party
|
|
1944
|
-
// url (singleStep.callUrl) and pass information about the workflow
|
|
1945
|
-
// in the headers (handled in getHeaders). QStash makes the request
|
|
1946
|
-
// to callUrl and returns the result to Workflow endpoint.
|
|
1947
|
-
// handleThirdPartyCallResult method sends the result of the third
|
|
1948
|
-
// party call to QStash.
|
|
1949
|
-
{
|
|
1950
|
-
headers,
|
|
1951
|
-
method: singleStep.callMethod,
|
|
1952
|
-
body: JSON.stringify(singleStep.callBody),
|
|
1953
|
-
url: singleStep.callUrl
|
|
1954
|
-
}
|
|
1955
|
-
) : (
|
|
1956
|
-
// if the step is not a third party call, we use workflow
|
|
1957
|
-
// endpoint (context.url) as URL when calling QStash. QStash
|
|
1958
|
-
// calls us back with the updated steps list.
|
|
1959
|
-
{
|
|
1960
|
-
headers,
|
|
1961
|
-
method: "POST",
|
|
1962
|
-
body: JSON.stringify(singleStep),
|
|
1963
|
-
url: this.context.url,
|
|
1964
|
-
notBefore: willWait ? singleStep.sleepUntil : void 0,
|
|
1965
|
-
delay: willWait ? singleStep.sleepFor : void 0
|
|
1966
|
-
}
|
|
1967
|
-
);
|
|
1968
|
-
})
|
|
1969
|
-
);
|
|
1970
|
-
const _result = result;
|
|
1971
|
-
await this.debug?.log("INFO", "SUBMIT_STEP", {
|
|
1972
|
-
messageIds: _result.map((message) => {
|
|
1973
|
-
return {
|
|
1974
|
-
message: message.messageId
|
|
1975
|
-
};
|
|
1976
|
-
})
|
|
1977
|
-
});
|
|
1978
|
-
throw new WorkflowAbort(steps[0].stepName, steps[0]);
|
|
1979
|
-
}
|
|
1980
2181
|
/**
|
|
1981
2182
|
* Get the promise by executing the lazt steps list. If there is a single
|
|
1982
2183
|
* step, we call `runSingle`. Otherwise `runParallel` is called.
|
|
@@ -2173,7 +2374,7 @@ var WorkflowApi = class extends BaseWorkflowApi {
|
|
|
2173
2374
|
};
|
|
2174
2375
|
|
|
2175
2376
|
// src/agents/index.ts
|
|
2176
|
-
import { createOpenAI
|
|
2377
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
2177
2378
|
|
|
2178
2379
|
// src/agents/agent.ts
|
|
2179
2380
|
import { z } from "zod";
|
|
@@ -2379,11 +2580,12 @@ var WorkflowAgents = class {
|
|
|
2379
2580
|
*/
|
|
2380
2581
|
openai(...params) {
|
|
2381
2582
|
const [model, settings] = params;
|
|
2382
|
-
const { baseURL, apiKey, ...otherSettings } = settings ?? {};
|
|
2583
|
+
const { baseURL, apiKey, callSettings, ...otherSettings } = settings ?? {};
|
|
2383
2584
|
const openaiModel = this.AISDKModel({
|
|
2384
2585
|
context: this.context,
|
|
2385
|
-
provider:
|
|
2386
|
-
providerParams: { baseURL, apiKey, compatibility: "strict" }
|
|
2586
|
+
provider: createOpenAI,
|
|
2587
|
+
providerParams: { baseURL, apiKey, compatibility: "strict" },
|
|
2588
|
+
agentCallParams: callSettings
|
|
2387
2589
|
});
|
|
2388
2590
|
return openaiModel(model, otherSettings);
|
|
2389
2591
|
}
|
|
@@ -2611,60 +2813,42 @@ var WorkflowContext = class {
|
|
|
2611
2813
|
}
|
|
2612
2814
|
await this.addStep(new LazySleepUntilStep(stepName, time));
|
|
2613
2815
|
}
|
|
2614
|
-
/**
|
|
2615
|
-
* Makes a third party call through QStash in order to make a
|
|
2616
|
-
* network call without consuming any runtime.
|
|
2617
|
-
*
|
|
2618
|
-
* ```ts
|
|
2619
|
-
* const { status, body } = await context.call<string>(
|
|
2620
|
-
* "post call step",
|
|
2621
|
-
* {
|
|
2622
|
-
* url: "https://www.some-endpoint.com/api",
|
|
2623
|
-
* method: "POST",
|
|
2624
|
-
* body: "my-payload"
|
|
2625
|
-
* }
|
|
2626
|
-
* );
|
|
2627
|
-
* ```
|
|
2628
|
-
*
|
|
2629
|
-
* tries to parse the result of the request as JSON. If it's
|
|
2630
|
-
* not a JSON which can be parsed, simply returns the response
|
|
2631
|
-
* body as it is.
|
|
2632
|
-
*
|
|
2633
|
-
* @param stepName
|
|
2634
|
-
* @param url url to call
|
|
2635
|
-
* @param method call method. "GET" by default.
|
|
2636
|
-
* @param body call body
|
|
2637
|
-
* @param headers call headers
|
|
2638
|
-
* @param retries number of call retries. 0 by default
|
|
2639
|
-
* @param timeout max duration to wait for the endpoint to respond. in seconds.
|
|
2640
|
-
* @returns call result as {
|
|
2641
|
-
* status: number;
|
|
2642
|
-
* body: unknown;
|
|
2643
|
-
* header: Record<string, string[]>
|
|
2644
|
-
* }
|
|
2645
|
-
*/
|
|
2646
2816
|
async call(stepName, settings) {
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2817
|
+
let callStep;
|
|
2818
|
+
if ("workflow" in settings) {
|
|
2819
|
+
const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
|
|
2820
|
+
callStep = new LazyCallStep(
|
|
2821
|
+
stepName,
|
|
2822
|
+
url,
|
|
2823
|
+
"POST",
|
|
2824
|
+
settings.body,
|
|
2825
|
+
settings.headers || {},
|
|
2826
|
+
settings.retries || 0,
|
|
2827
|
+
settings.timeout,
|
|
2828
|
+
settings.flowControl ?? settings.workflow.options.flowControl
|
|
2829
|
+
);
|
|
2830
|
+
} else {
|
|
2831
|
+
const {
|
|
2832
|
+
url,
|
|
2833
|
+
method = "GET",
|
|
2834
|
+
body,
|
|
2835
|
+
headers = {},
|
|
2836
|
+
retries = 0,
|
|
2837
|
+
timeout,
|
|
2838
|
+
flowControl
|
|
2839
|
+
} = settings;
|
|
2840
|
+
callStep = new LazyCallStep(
|
|
2658
2841
|
stepName,
|
|
2659
2842
|
url,
|
|
2660
2843
|
method,
|
|
2661
|
-
|
|
2844
|
+
body,
|
|
2662
2845
|
headers,
|
|
2663
2846
|
retries,
|
|
2664
2847
|
timeout,
|
|
2665
2848
|
flowControl
|
|
2666
|
-
)
|
|
2667
|
-
|
|
2849
|
+
);
|
|
2850
|
+
}
|
|
2851
|
+
return await this.addStep(callStep);
|
|
2668
2852
|
}
|
|
2669
2853
|
/**
|
|
2670
2854
|
* Pauses workflow execution until a specific event occurs or a timeout is reached.
|
|
@@ -3332,8 +3516,8 @@ export {
|
|
|
3332
3516
|
getWorkflowRunId,
|
|
3333
3517
|
StepTypes,
|
|
3334
3518
|
triggerFirstInvocation,
|
|
3335
|
-
serveManyBase,
|
|
3336
3519
|
WorkflowTool,
|
|
3520
|
+
serveManyBase,
|
|
3337
3521
|
WorkflowContext,
|
|
3338
3522
|
WorkflowLogger,
|
|
3339
3523
|
serveBase,
|