@upstash/workflow 0.2.23 → 0.3.0-rc1
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 +4 -6
- package/astro.d.ts +4 -6
- package/astro.js +892 -960
- package/astro.mjs +1 -1
- package/{chunk-GZRDB6Z5.mjs → chunk-2Z32SOYM.mjs} +850 -951
- package/cloudflare.d.mts +4 -6
- package/cloudflare.d.ts +4 -6
- package/cloudflare.js +892 -960
- package/cloudflare.mjs +1 -1
- package/express.d.mts +4 -6
- package/express.d.ts +4 -6
- package/express.js +902 -965
- package/express.mjs +11 -6
- package/h3.d.mts +4 -6
- package/h3.d.ts +4 -6
- package/h3.js +906 -973
- package/h3.mjs +16 -15
- package/hono.d.mts +4 -6
- package/hono.d.ts +4 -6
- package/hono.js +892 -960
- package/hono.mjs +1 -1
- package/index.d.mts +98 -66
- package/index.d.ts +98 -66
- package/index.js +886 -978
- package/index.mjs +30 -23
- package/nextjs.d.mts +6 -8
- package/nextjs.d.ts +6 -8
- package/nextjs.js +893 -961
- package/nextjs.mjs +2 -2
- package/package.json +1 -1
- package/{serve-many-BCV7INWe.d.ts → serve-many-DhB8-zPD.d.mts} +2 -2
- package/{serve-many-B5Vbacm6.d.mts → serve-many-qnfynN1x.d.ts} +2 -2
- package/solidjs.d.mts +2 -4
- package/solidjs.d.ts +2 -4
- package/solidjs.js +860 -924
- package/solidjs.mjs +6 -2
- package/svelte.d.mts +7 -10
- package/svelte.d.ts +7 -10
- package/svelte.js +905 -966
- package/svelte.mjs +14 -7
- package/tanstack.d.mts +4 -6
- package/tanstack.d.ts +4 -6
- package/tanstack.js +892 -960
- package/tanstack.mjs +1 -1
- package/{types-BD06btU6.d.ts → types-pEje3VEB.d.mts} +193 -537
- package/{types-BD06btU6.d.mts → types-pEje3VEB.d.ts} +193 -537
package/express.js
CHANGED
|
@@ -31,20 +31,22 @@ var WORKFLOW_ID_HEADER = "Upstash-Workflow-RunId";
|
|
|
31
31
|
var WORKFLOW_INIT_HEADER = "Upstash-Workflow-Init";
|
|
32
32
|
var WORKFLOW_URL_HEADER = "Upstash-Workflow-Url";
|
|
33
33
|
var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
|
|
34
|
+
var WORKFLOW_FAILURE_CALLBACK_HEADER = "Upstash-Workflow-Failure-Callback";
|
|
34
35
|
var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
|
|
35
36
|
var WORKFLOW_INVOKE_COUNT_HEADER = "Upstash-Workflow-Invoke-Count";
|
|
36
37
|
var WORKFLOW_LABEL_HEADER = "Upstash-Label";
|
|
38
|
+
var WORKFLOW_UNKOWN_SDK_VERSION_HEADER = "Upstash-Workflow-Unknown-Sdk";
|
|
39
|
+
var WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER = "upstash-workflow-trigger-by-sdk";
|
|
37
40
|
var WORKFLOW_PROTOCOL_VERSION = "1";
|
|
38
41
|
var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
|
|
39
42
|
var DEFAULT_CONTENT_TYPE = "application/json";
|
|
40
43
|
var NO_CONCURRENCY = 1;
|
|
41
44
|
var DEFAULT_RETRIES = 3;
|
|
42
|
-
var VERSION = "
|
|
45
|
+
var VERSION = "v1.0.0";
|
|
43
46
|
var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
|
|
44
47
|
var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
|
|
45
48
|
var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
|
|
46
49
|
var TELEMETRY_HEADER_RUNTIME = "Upstash-Telemetry-Runtime";
|
|
47
|
-
var TELEMETRY_HEADER_AGENT = "Upstash-Telemetry-Agent";
|
|
48
50
|
|
|
49
51
|
// src/client/utils.ts
|
|
50
52
|
var import_qstash2 = require("@upstash/qstash");
|
|
@@ -58,26 +60,36 @@ var WorkflowError = class extends import_qstash.QstashError {
|
|
|
58
60
|
}
|
|
59
61
|
};
|
|
60
62
|
var WorkflowAbort = class extends Error {
|
|
61
|
-
stepInfo;
|
|
62
63
|
stepName;
|
|
64
|
+
stepInfo;
|
|
63
65
|
/**
|
|
64
|
-
* whether workflow is to be canceled on abort
|
|
65
|
-
*/
|
|
66
|
-
cancelWorkflow;
|
|
67
|
-
/**
|
|
68
|
-
*
|
|
69
66
|
* @param stepName name of the aborting step
|
|
70
67
|
* @param stepInfo step information
|
|
71
|
-
* @param cancelWorkflow
|
|
72
68
|
*/
|
|
73
|
-
constructor(stepName, stepInfo
|
|
69
|
+
constructor(stepName, stepInfo) {
|
|
74
70
|
super(
|
|
75
71
|
`This is an Upstash Workflow error thrown after a step executes. It is expected to be raised. Make sure that you await for each step. Also, if you are using try/catch blocks, you should not wrap context.run/sleep/sleepUntil/call methods with try/catch. Aborting workflow after executing step '${stepName}'.`
|
|
76
72
|
);
|
|
77
73
|
this.name = "WorkflowAbort";
|
|
78
74
|
this.stepName = stepName;
|
|
79
75
|
this.stepInfo = stepInfo;
|
|
80
|
-
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var WorkflowAuthError = class extends WorkflowAbort {
|
|
79
|
+
/**
|
|
80
|
+
* @param stepName name of the step found during authorization
|
|
81
|
+
*/
|
|
82
|
+
constructor(stepName) {
|
|
83
|
+
super(stepName);
|
|
84
|
+
this.name = "WorkflowAuthError";
|
|
85
|
+
this.message = `This is an Upstash Workflow error thrown during authorization check. Found step '${stepName}' during dry-run.`;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
var WorkflowCancelAbort = class extends WorkflowAbort {
|
|
89
|
+
constructor() {
|
|
90
|
+
super("cancel");
|
|
91
|
+
this.name = "WorkflowCancelAbort";
|
|
92
|
+
this.message = "Workflow has been canceled by user via context.cancel().";
|
|
81
93
|
}
|
|
82
94
|
};
|
|
83
95
|
var WorkflowNonRetryableError = class extends WorkflowAbort {
|
|
@@ -85,22 +97,22 @@ var WorkflowNonRetryableError = class extends WorkflowAbort {
|
|
|
85
97
|
* @param message error message to be displayed
|
|
86
98
|
*/
|
|
87
99
|
constructor(message) {
|
|
88
|
-
super("
|
|
100
|
+
super("non-retryable-error");
|
|
89
101
|
this.name = "WorkflowNonRetryableError";
|
|
90
|
-
|
|
102
|
+
this.message = message ?? "Workflow failed with non-retryable error.";
|
|
91
103
|
}
|
|
92
104
|
};
|
|
93
105
|
var WorkflowRetryAfterError = class extends WorkflowAbort {
|
|
94
106
|
retryAfter;
|
|
95
107
|
/**
|
|
96
|
-
* @param retryAfter time in seconds after which the workflow should be retried
|
|
97
108
|
* @param message error message to be displayed
|
|
109
|
+
* @param retryAfter time in seconds after which the workflow should be retried
|
|
98
110
|
*/
|
|
99
111
|
constructor(message, retryAfter) {
|
|
100
|
-
super("retry"
|
|
112
|
+
super("retry-after-error");
|
|
101
113
|
this.name = "WorkflowRetryAfterError";
|
|
114
|
+
this.message = message;
|
|
102
115
|
this.retryAfter = retryAfter;
|
|
103
|
-
if (message) this.message = message;
|
|
104
116
|
}
|
|
105
117
|
};
|
|
106
118
|
var formatWorkflowError = (error) => {
|
|
@@ -152,15 +164,21 @@ var makeCancelRequest = async (requester, workflowRunId) => {
|
|
|
152
164
|
});
|
|
153
165
|
return true;
|
|
154
166
|
};
|
|
155
|
-
var getSteps = async (requester, workflowRunId, messageId,
|
|
167
|
+
var getSteps = async (requester, workflowRunId, messageId, dispatchDebug) => {
|
|
156
168
|
try {
|
|
157
169
|
const steps = await requester.request({
|
|
158
170
|
path: ["v2", "workflows", "runs", workflowRunId],
|
|
159
171
|
parseResponseAsJson: true
|
|
160
172
|
});
|
|
173
|
+
if (steps.length === 1) {
|
|
174
|
+
return {
|
|
175
|
+
steps,
|
|
176
|
+
workflowRunEnded: false
|
|
177
|
+
};
|
|
178
|
+
}
|
|
161
179
|
if (!messageId) {
|
|
162
|
-
await
|
|
163
|
-
|
|
180
|
+
await dispatchDebug?.("onInfo", {
|
|
181
|
+
info: `Pulled ${steps.length} steps from QStashand returned them without filtering with messageId.`
|
|
164
182
|
});
|
|
165
183
|
return { steps, workflowRunEnded: false };
|
|
166
184
|
} else {
|
|
@@ -169,16 +187,15 @@ var getSteps = async (requester, workflowRunId, messageId, debug) => {
|
|
|
169
187
|
return { steps: [], workflowRunEnded: false };
|
|
170
188
|
}
|
|
171
189
|
const filteredSteps = steps.slice(0, index + 1);
|
|
172
|
-
await
|
|
173
|
-
|
|
190
|
+
await dispatchDebug?.("onInfo", {
|
|
191
|
+
info: `Pulled ${steps.length} steps from QStash and filtered them to ${filteredSteps.length} using messageId.`
|
|
174
192
|
});
|
|
175
193
|
return { steps: filteredSteps, workflowRunEnded: false };
|
|
176
194
|
}
|
|
177
195
|
} catch (error) {
|
|
178
196
|
if (isInstanceOf(error, import_qstash2.QstashError) && error.status === 404) {
|
|
179
|
-
await
|
|
180
|
-
|
|
181
|
-
error
|
|
197
|
+
await dispatchDebug?.("onWarning", {
|
|
198
|
+
warning: "Couldn't fetch workflow run steps. This can happen if the workflow run succesfully ends before some callback is executed."
|
|
182
199
|
});
|
|
183
200
|
return { steps: void 0, workflowRunEnded: true };
|
|
184
201
|
} else {
|
|
@@ -248,6 +265,15 @@ function getQStashUrl(qstashClient) {
|
|
|
248
265
|
function getEventId() {
|
|
249
266
|
return `evt_${nanoid(15)}`;
|
|
250
267
|
}
|
|
268
|
+
function stringifyBody(body) {
|
|
269
|
+
if (body === void 0) {
|
|
270
|
+
return void 0;
|
|
271
|
+
}
|
|
272
|
+
if (typeof body === "string") {
|
|
273
|
+
return body;
|
|
274
|
+
}
|
|
275
|
+
return JSON.stringify(body);
|
|
276
|
+
}
|
|
251
277
|
|
|
252
278
|
// node_modules/neverthrow/dist/index.es.js
|
|
253
279
|
var defaultErrorConfig = {
|
|
@@ -589,9 +615,9 @@ var Ok = class {
|
|
|
589
615
|
}
|
|
590
616
|
safeUnwrap() {
|
|
591
617
|
const value = this.value;
|
|
592
|
-
return function* () {
|
|
618
|
+
return (function* () {
|
|
593
619
|
return value;
|
|
594
|
-
}();
|
|
620
|
+
})();
|
|
595
621
|
}
|
|
596
622
|
_unsafeUnwrap(_) {
|
|
597
623
|
return this.value;
|
|
@@ -650,10 +676,10 @@ var Err = class {
|
|
|
650
676
|
}
|
|
651
677
|
safeUnwrap() {
|
|
652
678
|
const error = this.error;
|
|
653
|
-
return function* () {
|
|
679
|
+
return (function* () {
|
|
654
680
|
yield err(error);
|
|
655
681
|
throw new Error("Do not use this generator out of `safeTry`");
|
|
656
|
-
}();
|
|
682
|
+
})();
|
|
657
683
|
}
|
|
658
684
|
_unsafeUnwrap(config) {
|
|
659
685
|
throw createNeverThrowError("Called `_unsafeUnwrap` on an Err", this, config);
|
|
@@ -691,23 +717,26 @@ var triggerFirstInvocation = async (params) => {
|
|
|
691
717
|
invokeCount,
|
|
692
718
|
delay,
|
|
693
719
|
notBefore,
|
|
694
|
-
|
|
720
|
+
failureUrl,
|
|
721
|
+
retries,
|
|
722
|
+
retryDelay,
|
|
723
|
+
flowControl,
|
|
724
|
+
unknownSdk
|
|
695
725
|
}) => {
|
|
696
726
|
const { headers } = getHeaders({
|
|
697
727
|
initHeaderValue: "true",
|
|
698
728
|
workflowConfig: {
|
|
699
729
|
workflowRunId: workflowContext.workflowRunId,
|
|
700
730
|
workflowUrl: workflowContext.url,
|
|
701
|
-
failureUrl
|
|
702
|
-
retries
|
|
703
|
-
retryDelay
|
|
731
|
+
failureUrl,
|
|
732
|
+
retries,
|
|
733
|
+
retryDelay,
|
|
704
734
|
telemetry: telemetry2,
|
|
705
|
-
flowControl
|
|
735
|
+
flowControl,
|
|
706
736
|
useJSONContent: useJSONContent ?? false
|
|
707
737
|
},
|
|
708
738
|
invokeCount: invokeCount ?? 0,
|
|
709
|
-
userHeaders: workflowContext.headers
|
|
710
|
-
keepTriggerConfig
|
|
739
|
+
userHeaders: workflowContext.headers
|
|
711
740
|
});
|
|
712
741
|
if (workflowContext.headers.get("content-type")) {
|
|
713
742
|
headers["content-type"] = workflowContext.headers.get("content-type");
|
|
@@ -715,6 +744,9 @@ var triggerFirstInvocation = async (params) => {
|
|
|
715
744
|
if (useJSONContent) {
|
|
716
745
|
headers["content-type"] = "application/json";
|
|
717
746
|
}
|
|
747
|
+
if (unknownSdk) {
|
|
748
|
+
headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
|
|
749
|
+
}
|
|
718
750
|
if (workflowContext.label) {
|
|
719
751
|
headers[WORKFLOW_LABEL_HEADER] = workflowContext.label;
|
|
720
752
|
}
|
|
@@ -735,21 +767,15 @@ var triggerFirstInvocation = async (params) => {
|
|
|
735
767
|
for (let i = 0; i < results.length; i++) {
|
|
736
768
|
const result = results[i];
|
|
737
769
|
const invocationParams = firstInvocationParams[i];
|
|
770
|
+
invocationParams.middlewareManager?.assignContext(invocationParams.workflowContext);
|
|
738
771
|
if (result.deduplicated) {
|
|
739
|
-
await invocationParams.
|
|
740
|
-
|
|
741
|
-
headers: invocationBatch[i].headers,
|
|
742
|
-
requestPayload: invocationParams.workflowContext.requestPayload,
|
|
743
|
-
url: invocationParams.workflowContext.url,
|
|
744
|
-
messageId: result.messageId
|
|
772
|
+
await invocationParams.middlewareManager?.dispatchDebug("onWarning", {
|
|
773
|
+
warning: `Workflow run ${invocationParams.workflowContext.workflowRunId} already exists. A new one isn't created.`
|
|
745
774
|
});
|
|
746
775
|
invocationStatuses.push("workflow-run-already-exists");
|
|
747
776
|
} else {
|
|
748
|
-
await invocationParams.
|
|
749
|
-
|
|
750
|
-
requestPayload: invocationParams.workflowContext.requestPayload,
|
|
751
|
-
url: invocationParams.workflowContext.url,
|
|
752
|
-
messageId: result.messageId
|
|
777
|
+
await invocationParams.middlewareManager?.dispatchDebug("onInfo", {
|
|
778
|
+
info: `Workflow run started successfully with URL ${invocationParams.workflowContext.url}.`
|
|
753
779
|
});
|
|
754
780
|
invocationStatuses.push("success");
|
|
755
781
|
}
|
|
@@ -771,7 +797,7 @@ var triggerRouteFunction = async ({
|
|
|
771
797
|
onCleanup,
|
|
772
798
|
onStep,
|
|
773
799
|
onCancel,
|
|
774
|
-
|
|
800
|
+
middlewareManager
|
|
775
801
|
}) => {
|
|
776
802
|
try {
|
|
777
803
|
const result = await onStep();
|
|
@@ -780,27 +806,25 @@ var triggerRouteFunction = async ({
|
|
|
780
806
|
} catch (error) {
|
|
781
807
|
const error_ = error;
|
|
782
808
|
if (isInstanceOf(error, import_qstash3.QstashError) && error.status === 400) {
|
|
783
|
-
await
|
|
784
|
-
|
|
785
|
-
name: error.name,
|
|
786
|
-
errorMessage: error.message
|
|
809
|
+
await middlewareManager?.dispatchDebug("onWarning", {
|
|
810
|
+
warning: `Tried to append to a cancelled workflow. Exiting without publishing. Error: ${error.message}`
|
|
787
811
|
});
|
|
788
812
|
return ok("workflow-was-finished");
|
|
789
813
|
} else if (isInstanceOf(error_, WorkflowNonRetryableError) || isInstanceOf(error_, WorkflowRetryAfterError)) {
|
|
790
814
|
return ok(error_);
|
|
791
|
-
} else if (
|
|
792
|
-
return err(error_);
|
|
793
|
-
} else if (error_.cancelWorkflow) {
|
|
815
|
+
} else if (isInstanceOf(error_, WorkflowCancelAbort)) {
|
|
794
816
|
await onCancel();
|
|
795
817
|
return ok("workflow-finished");
|
|
796
|
-
} else {
|
|
818
|
+
} else if (isInstanceOf(error_, WorkflowAbort)) {
|
|
797
819
|
return ok("step-finished");
|
|
820
|
+
} else {
|
|
821
|
+
return err(error_);
|
|
798
822
|
}
|
|
799
823
|
}
|
|
800
824
|
};
|
|
801
|
-
var triggerWorkflowDelete = async (workflowContext, result,
|
|
802
|
-
await
|
|
803
|
-
|
|
825
|
+
var triggerWorkflowDelete = async (workflowContext, result, cancel = false, dispatchDebug) => {
|
|
826
|
+
await dispatchDebug?.("onInfo", {
|
|
827
|
+
info: `Deleting workflow run ${workflowContext.workflowRunId} from QStash` + (cancel ? " with cancel=true." : ".")
|
|
804
828
|
});
|
|
805
829
|
await workflowContext.qstashClient.http.request({
|
|
806
830
|
path: ["v2", "workflows", "runs", `${workflowContext.workflowRunId}?cancel=${cancel}`],
|
|
@@ -808,18 +832,16 @@ var triggerWorkflowDelete = async (workflowContext, result, debug, cancel = fals
|
|
|
808
832
|
parseResponseAsJson: false,
|
|
809
833
|
body: JSON.stringify(result)
|
|
810
834
|
});
|
|
811
|
-
await
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
`workflow run ${workflowContext.workflowRunId} deleted.`
|
|
815
|
-
);
|
|
835
|
+
await dispatchDebug?.("onInfo", {
|
|
836
|
+
info: `Workflow run ${workflowContext.workflowRunId} deleted from QStash successfully.`
|
|
837
|
+
});
|
|
816
838
|
};
|
|
817
839
|
var recreateUserHeaders = (headers) => {
|
|
818
840
|
const filteredHeaders = new Headers();
|
|
819
841
|
const pairs = headers.entries();
|
|
820
842
|
for (const [header, value] of pairs) {
|
|
821
843
|
const headerLowerCase = header.toLowerCase();
|
|
822
|
-
const isUserHeader = !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
844
|
+
const isUserHeader = headerLowerCase !== "upstash-region" && !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
823
845
|
!headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && // https://blog.cloudflare.com/preventing-request-loops-using-cdn-loop/
|
|
824
846
|
headerLowerCase !== "cf-connecting-ip" && headerLowerCase !== "cdn-loop" && headerLowerCase !== "cf-ew-via" && headerLowerCase !== "cf-ray" && // For Render https://render.com
|
|
825
847
|
headerLowerCase !== "render-proxy-ttl" || headerLowerCase === WORKFLOW_LABEL_HEADER.toLocaleLowerCase();
|
|
@@ -834,12 +856,8 @@ var handleThirdPartyCallResult = async ({
|
|
|
834
856
|
requestPayload,
|
|
835
857
|
client,
|
|
836
858
|
workflowUrl,
|
|
837
|
-
failureUrl,
|
|
838
|
-
retries,
|
|
839
|
-
retryDelay,
|
|
840
859
|
telemetry: telemetry2,
|
|
841
|
-
|
|
842
|
-
debug
|
|
860
|
+
middlewareManager
|
|
843
861
|
}) => {
|
|
844
862
|
try {
|
|
845
863
|
if (request.headers.get("Upstash-Workflow-Callback")) {
|
|
@@ -856,7 +874,7 @@ var handleThirdPartyCallResult = async ({
|
|
|
856
874
|
client.http,
|
|
857
875
|
workflowRunId2,
|
|
858
876
|
messageId,
|
|
859
|
-
|
|
877
|
+
middlewareManager?.dispatchDebug.bind(middlewareManager)
|
|
860
878
|
);
|
|
861
879
|
if (workflowRunEnded) {
|
|
862
880
|
return ok("workflow-ended");
|
|
@@ -870,9 +888,8 @@ var handleThirdPartyCallResult = async ({
|
|
|
870
888
|
}
|
|
871
889
|
const callbackMessage = JSON.parse(callbackPayload);
|
|
872
890
|
if (!(callbackMessage.status >= 200 && callbackMessage.status < 300) && callbackMessage.maxRetries && callbackMessage.retried !== callbackMessage.maxRetries) {
|
|
873
|
-
await
|
|
874
|
-
|
|
875
|
-
body: atob(callbackMessage.body ?? "")
|
|
891
|
+
await middlewareManager?.dispatchDebug("onWarning", {
|
|
892
|
+
warning: `Third party call returned status ${callbackMessage.status}. Retrying (${callbackMessage.retried} out of ${callbackMessage.maxRetries}).`
|
|
876
893
|
});
|
|
877
894
|
console.warn(
|
|
878
895
|
`Workflow Warning: "context.call" failed with status ${callbackMessage.status} and will retry (retried ${callbackMessage.retried ?? 0} out of ${callbackMessage.maxRetries} times). Error Message:
|
|
@@ -905,11 +922,7 @@ ${atob(callbackMessage.body ?? "")}`
|
|
|
905
922
|
workflowConfig: {
|
|
906
923
|
workflowRunId,
|
|
907
924
|
workflowUrl,
|
|
908
|
-
|
|
909
|
-
retries,
|
|
910
|
-
retryDelay,
|
|
911
|
-
telemetry: telemetry2,
|
|
912
|
-
flowControl
|
|
925
|
+
telemetry: telemetry2
|
|
913
926
|
},
|
|
914
927
|
userHeaders,
|
|
915
928
|
invokeCount: Number(invokeCount)
|
|
@@ -926,19 +939,17 @@ ${atob(callbackMessage.body ?? "")}`
|
|
|
926
939
|
out: JSON.stringify(callResponse),
|
|
927
940
|
concurrent: Number(concurrentString)
|
|
928
941
|
};
|
|
929
|
-
await
|
|
930
|
-
|
|
931
|
-
headers: requestHeaders,
|
|
932
|
-
url: workflowUrl
|
|
942
|
+
await middlewareManager?.dispatchDebug("onInfo", {
|
|
943
|
+
info: `Submitting third party call result, step ${stepName} (${stepIdString}).`
|
|
933
944
|
});
|
|
934
|
-
|
|
945
|
+
await client.publishJSON({
|
|
935
946
|
headers: requestHeaders,
|
|
936
947
|
method: "POST",
|
|
937
948
|
body: callResultStep,
|
|
938
949
|
url: workflowUrl
|
|
939
950
|
});
|
|
940
|
-
await
|
|
941
|
-
|
|
951
|
+
await middlewareManager?.dispatchDebug("onInfo", {
|
|
952
|
+
info: `Third party call result submitted successfully, step ${stepName} (${stepIdString}).`
|
|
942
953
|
});
|
|
943
954
|
return ok("is-call-return");
|
|
944
955
|
} else {
|
|
@@ -996,8 +1007,8 @@ var BaseLazyStep = class _BaseLazyStep {
|
|
|
996
1007
|
);
|
|
997
1008
|
}
|
|
998
1009
|
if (typeof stepName !== "string") {
|
|
999
|
-
|
|
1000
|
-
|
|
1010
|
+
throw new WorkflowError(
|
|
1011
|
+
`A workflow step name must be a string. Received "${stepName}" (${typeof stepName}).`
|
|
1001
1012
|
);
|
|
1002
1013
|
}
|
|
1003
1014
|
this.stepName = stepName;
|
|
@@ -1059,12 +1070,8 @@ var BaseLazyStep = class _BaseLazyStep {
|
|
|
1059
1070
|
workflowConfig: {
|
|
1060
1071
|
workflowRunId: context.workflowRunId,
|
|
1061
1072
|
workflowUrl: context.url,
|
|
1062
|
-
failureUrl: context.failureUrl,
|
|
1063
|
-
retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
|
|
1064
|
-
retryDelay: context.retryDelay,
|
|
1065
1073
|
useJSONContent: false,
|
|
1066
|
-
telemetry: telemetry2
|
|
1067
|
-
flowControl: context.flowControl
|
|
1074
|
+
telemetry: telemetry2
|
|
1068
1075
|
},
|
|
1069
1076
|
userHeaders: context.headers,
|
|
1070
1077
|
invokeCount,
|
|
@@ -1080,9 +1087,6 @@ var BaseLazyStep = class _BaseLazyStep {
|
|
|
1080
1087
|
body,
|
|
1081
1088
|
headers,
|
|
1082
1089
|
method: "POST",
|
|
1083
|
-
retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
|
|
1084
|
-
retryDelay: context.retryDelay,
|
|
1085
|
-
flowControl: context.flowControl,
|
|
1086
1090
|
url: context.url
|
|
1087
1091
|
}
|
|
1088
1092
|
]);
|
|
@@ -1153,9 +1157,6 @@ var LazySleepStep = class extends BaseLazyStep {
|
|
|
1153
1157
|
headers,
|
|
1154
1158
|
method: "POST",
|
|
1155
1159
|
url: context.url,
|
|
1156
|
-
retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
|
|
1157
|
-
retryDelay: context.retryDelay,
|
|
1158
|
-
flowControl: context.flowControl,
|
|
1159
1160
|
delay: isParallel ? void 0 : this.sleep
|
|
1160
1161
|
}
|
|
1161
1162
|
]);
|
|
@@ -1198,9 +1199,6 @@ var LazySleepUntilStep = class extends BaseLazyStep {
|
|
|
1198
1199
|
headers,
|
|
1199
1200
|
method: "POST",
|
|
1200
1201
|
url: context.url,
|
|
1201
|
-
retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
|
|
1202
|
-
retryDelay: context.retryDelay,
|
|
1203
|
-
flowControl: context.flowControl,
|
|
1204
1202
|
notBefore: isParallel ? void 0 : this.sleepUntil
|
|
1205
1203
|
}
|
|
1206
1204
|
]);
|
|
@@ -1215,20 +1213,18 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
|
|
|
1215
1213
|
retryDelay;
|
|
1216
1214
|
timeout;
|
|
1217
1215
|
flowControl;
|
|
1218
|
-
stringifyBody;
|
|
1219
1216
|
stepType = "Call";
|
|
1220
1217
|
allowUndefinedOut = false;
|
|
1221
|
-
constructor(
|
|
1222
|
-
super(context, stepName);
|
|
1223
|
-
this.url = url;
|
|
1224
|
-
this.method = method;
|
|
1225
|
-
this.body = body;
|
|
1226
|
-
this.headers = headers;
|
|
1227
|
-
this.retries = retries;
|
|
1228
|
-
this.retryDelay = retryDelay;
|
|
1229
|
-
this.timeout = timeout;
|
|
1230
|
-
this.flowControl = flowControl;
|
|
1231
|
-
this.stringifyBody = stringifyBody;
|
|
1218
|
+
constructor(params) {
|
|
1219
|
+
super(params.context, params.stepName);
|
|
1220
|
+
this.url = params.url;
|
|
1221
|
+
this.method = params.method ?? "GET";
|
|
1222
|
+
this.body = params.body;
|
|
1223
|
+
this.headers = params.headers ?? {};
|
|
1224
|
+
this.retries = params.retries ?? 0;
|
|
1225
|
+
this.retryDelay = params.retryDelay;
|
|
1226
|
+
this.timeout = params.timeout;
|
|
1227
|
+
this.flowControl = params.flowControl;
|
|
1232
1228
|
}
|
|
1233
1229
|
getPlanStep(concurrent, targetStep) {
|
|
1234
1230
|
return {
|
|
@@ -1325,7 +1321,7 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
|
|
|
1325
1321
|
"Upstash-Callback-Workflow-CallType": "fromCallback",
|
|
1326
1322
|
"Upstash-Callback-Workflow-Init": "false",
|
|
1327
1323
|
"Upstash-Callback-Workflow-Url": context.url,
|
|
1328
|
-
"Upstash-Callback-Feature-Set": "LazyFetch,InitialBody,WF_DetectTrigger",
|
|
1324
|
+
"Upstash-Callback-Feature-Set": "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig",
|
|
1329
1325
|
"Upstash-Callback-Forward-Upstash-Workflow-Callback": "true",
|
|
1330
1326
|
"Upstash-Callback-Forward-Upstash-Workflow-StepId": step.stepId.toString(),
|
|
1331
1327
|
"Upstash-Callback-Forward-Upstash-Workflow-StepName": this.stepName,
|
|
@@ -1338,22 +1334,10 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
|
|
|
1338
1334
|
};
|
|
1339
1335
|
}
|
|
1340
1336
|
async submitStep({ context, headers }) {
|
|
1341
|
-
let callBody;
|
|
1342
|
-
if (this.stringifyBody) {
|
|
1343
|
-
callBody = JSON.stringify(this.body);
|
|
1344
|
-
} else {
|
|
1345
|
-
if (typeof this.body === "string") {
|
|
1346
|
-
callBody = this.body;
|
|
1347
|
-
} else {
|
|
1348
|
-
throw new WorkflowError(
|
|
1349
|
-
"When stringifyBody is false, body must be a string. Please check the body type of your call step."
|
|
1350
|
-
);
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
1337
|
return await context.qstashClient.batch([
|
|
1354
1338
|
{
|
|
1355
1339
|
headers,
|
|
1356
|
-
body:
|
|
1340
|
+
body: this.body,
|
|
1357
1341
|
method: this.method,
|
|
1358
1342
|
url: this.url,
|
|
1359
1343
|
retries: DEFAULT_RETRIES === this.retries ? void 0 : this.retries,
|
|
@@ -1473,28 +1457,10 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1473
1457
|
* workflow id of the invoked workflow
|
|
1474
1458
|
*/
|
|
1475
1459
|
workflowId;
|
|
1476
|
-
constructor(context, stepName, {
|
|
1477
|
-
workflow,
|
|
1478
|
-
body,
|
|
1479
|
-
headers = {},
|
|
1480
|
-
workflowRunId,
|
|
1481
|
-
retries,
|
|
1482
|
-
retryDelay,
|
|
1483
|
-
flowControl,
|
|
1484
|
-
stringifyBody = true
|
|
1485
|
-
}) {
|
|
1460
|
+
constructor(context, stepName, params) {
|
|
1486
1461
|
super(context, stepName);
|
|
1487
|
-
this.params =
|
|
1488
|
-
|
|
1489
|
-
body,
|
|
1490
|
-
headers,
|
|
1491
|
-
workflowRunId: getWorkflowRunId(workflowRunId),
|
|
1492
|
-
retries,
|
|
1493
|
-
retryDelay,
|
|
1494
|
-
flowControl,
|
|
1495
|
-
stringifyBody
|
|
1496
|
-
};
|
|
1497
|
-
const { workflowId } = workflow;
|
|
1462
|
+
this.params = params;
|
|
1463
|
+
const { workflowId } = params.workflow;
|
|
1498
1464
|
if (!workflowId) {
|
|
1499
1465
|
throw new WorkflowError("You can only invoke workflow which has a workflowId");
|
|
1500
1466
|
}
|
|
@@ -1534,11 +1500,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1534
1500
|
workflowConfig: {
|
|
1535
1501
|
workflowRunId: context.workflowRunId,
|
|
1536
1502
|
workflowUrl: context.url,
|
|
1537
|
-
failureUrl: context.failureUrl,
|
|
1538
|
-
retries: context.retries,
|
|
1539
|
-
retryDelay: context.retryDelay,
|
|
1540
1503
|
telemetry: telemetry2,
|
|
1541
|
-
flowControl: context.flowControl,
|
|
1542
1504
|
useJSONContent: false
|
|
1543
1505
|
},
|
|
1544
1506
|
userHeaders: context.headers,
|
|
@@ -1548,20 +1510,8 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1548
1510
|
invokerHeaders[key] = value;
|
|
1549
1511
|
});
|
|
1550
1512
|
invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
|
|
1551
|
-
let invokeBody;
|
|
1552
|
-
if (this.params.stringifyBody) {
|
|
1553
|
-
invokeBody = JSON.stringify(this.params.body);
|
|
1554
|
-
} else {
|
|
1555
|
-
if (typeof this.params.body === "string") {
|
|
1556
|
-
invokeBody = this.params.body;
|
|
1557
|
-
} else {
|
|
1558
|
-
throw new WorkflowError(
|
|
1559
|
-
"When stringifyBody is false, body must be a string. Please check the body type of your invoke step."
|
|
1560
|
-
);
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
1513
|
const request = {
|
|
1564
|
-
body:
|
|
1514
|
+
body: stringifyBody(this.params.body),
|
|
1565
1515
|
headers: Object.fromEntries(
|
|
1566
1516
|
Object.entries(invokerHeaders).map((pairs) => [pairs[0], [pairs[1]]])
|
|
1567
1517
|
),
|
|
@@ -1572,34 +1522,19 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1572
1522
|
return JSON.stringify(request);
|
|
1573
1523
|
}
|
|
1574
1524
|
getHeaders({ context, telemetry: telemetry2, invokeCount }) {
|
|
1575
|
-
const {
|
|
1576
|
-
workflow,
|
|
1577
|
-
headers = {},
|
|
1578
|
-
workflowRunId = getWorkflowRunId(),
|
|
1579
|
-
retries,
|
|
1580
|
-
retryDelay,
|
|
1581
|
-
flowControl
|
|
1582
|
-
} = this.params;
|
|
1525
|
+
const { workflow, headers = {}, workflowRunId, retries, retryDelay, flowControl } = this.params;
|
|
1583
1526
|
const newUrl = context.url.replace(/[^/]+$/, this.workflowId);
|
|
1584
|
-
const {
|
|
1585
|
-
retries: workflowRetries,
|
|
1586
|
-
retryDelay: workflowRetryDelay,
|
|
1587
|
-
failureFunction,
|
|
1588
|
-
failureUrl,
|
|
1589
|
-
useJSONContent,
|
|
1590
|
-
flowControl: workflowFlowControl
|
|
1591
|
-
} = workflow.options;
|
|
1592
1527
|
const { headers: triggerHeaders, contentType } = getHeaders({
|
|
1593
1528
|
initHeaderValue: "true",
|
|
1594
1529
|
workflowConfig: {
|
|
1595
|
-
workflowRunId,
|
|
1530
|
+
workflowRunId: getWorkflowRunId(workflowRunId),
|
|
1596
1531
|
workflowUrl: newUrl,
|
|
1597
|
-
retries
|
|
1598
|
-
retryDelay
|
|
1532
|
+
retries,
|
|
1533
|
+
retryDelay,
|
|
1599
1534
|
telemetry: telemetry2,
|
|
1600
|
-
failureUrl:
|
|
1601
|
-
flowControl
|
|
1602
|
-
useJSONContent: useJSONContent ?? false
|
|
1535
|
+
failureUrl: newUrl,
|
|
1536
|
+
flowControl,
|
|
1537
|
+
useJSONContent: workflow.useJSONContent ?? false
|
|
1603
1538
|
},
|
|
1604
1539
|
invokeCount: invokeCount + 1,
|
|
1605
1540
|
userHeaders: new Headers(headers)
|
|
@@ -1701,20 +1636,6 @@ var LazyWaitForEventStep = class extends LazyWaitEventStep {
|
|
|
1701
1636
|
}
|
|
1702
1637
|
};
|
|
1703
1638
|
|
|
1704
|
-
// src/agents/constants.ts
|
|
1705
|
-
var AGENT_NAME_HEADER = "upstash-agent-name";
|
|
1706
|
-
var MANAGER_AGENT_PROMPT = `You are an agent orchestrating other AI Agents.
|
|
1707
|
-
|
|
1708
|
-
These other agents have tools available to them.
|
|
1709
|
-
|
|
1710
|
-
Given a prompt, utilize these agents to address requests.
|
|
1711
|
-
|
|
1712
|
-
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.
|
|
1713
|
-
|
|
1714
|
-
Avoid calling the same agent twice in one turn. Instead, prefer to call it once but provide everything
|
|
1715
|
-
you need from that agent.
|
|
1716
|
-
`;
|
|
1717
|
-
|
|
1718
1639
|
// src/qstash/headers.ts
|
|
1719
1640
|
var WorkflowHeaders = class {
|
|
1720
1641
|
userHeaders;
|
|
@@ -1723,14 +1644,15 @@ var WorkflowHeaders = class {
|
|
|
1723
1644
|
initHeaderValue;
|
|
1724
1645
|
stepInfo;
|
|
1725
1646
|
headers;
|
|
1726
|
-
|
|
1647
|
+
/**
|
|
1648
|
+
* @param params workflow header parameters
|
|
1649
|
+
*/
|
|
1727
1650
|
constructor({
|
|
1728
1651
|
userHeaders,
|
|
1729
1652
|
workflowConfig,
|
|
1730
1653
|
invokeCount,
|
|
1731
1654
|
initHeaderValue,
|
|
1732
|
-
stepInfo
|
|
1733
|
-
keepTriggerConfig
|
|
1655
|
+
stepInfo
|
|
1734
1656
|
}) {
|
|
1735
1657
|
this.userHeaders = userHeaders;
|
|
1736
1658
|
this.workflowConfig = workflowConfig;
|
|
@@ -1742,7 +1664,6 @@ var WorkflowHeaders = class {
|
|
|
1742
1664
|
workflowHeaders: {},
|
|
1743
1665
|
failureHeaders: {}
|
|
1744
1666
|
};
|
|
1745
|
-
this.keepTriggerConfig = keepTriggerConfig;
|
|
1746
1667
|
}
|
|
1747
1668
|
getHeaders() {
|
|
1748
1669
|
this.addBaseHeaders();
|
|
@@ -1761,10 +1682,9 @@ var WorkflowHeaders = class {
|
|
|
1761
1682
|
[WORKFLOW_INIT_HEADER]: this.initHeaderValue,
|
|
1762
1683
|
[WORKFLOW_ID_HEADER]: this.workflowConfig.workflowRunId,
|
|
1763
1684
|
[WORKFLOW_URL_HEADER]: this.workflowConfig.workflowUrl,
|
|
1764
|
-
[WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody,WF_DetectTrigger
|
|
1685
|
+
[WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig",
|
|
1765
1686
|
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
|
|
1766
|
-
...this.workflowConfig.telemetry ? getTelemetryHeaders(this.workflowConfig.telemetry) : {}
|
|
1767
|
-
...this.workflowConfig.telemetry && this.stepInfo?.lazyStep instanceof LazyCallStep && this.stepInfo.lazyStep.headers[AGENT_NAME_HEADER] ? { [TELEMETRY_HEADER_AGENT]: "true" } : {}
|
|
1687
|
+
...this.workflowConfig.telemetry ? getTelemetryHeaders(this.workflowConfig.telemetry) : {}
|
|
1768
1688
|
};
|
|
1769
1689
|
if (this.stepInfo?.lazyStep.stepType !== "Call") {
|
|
1770
1690
|
this.headers.rawHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
|
|
@@ -1832,12 +1752,12 @@ var WorkflowHeaders = class {
|
|
|
1832
1752
|
}
|
|
1833
1753
|
this.headers.workflowHeaders["Failure-Callback"] = this.workflowConfig.failureUrl;
|
|
1834
1754
|
this.headers.failureHeaders[`Forward-${WORKFLOW_FAILURE_HEADER}`] = "true";
|
|
1835
|
-
this.headers.failureHeaders[`Forward
|
|
1755
|
+
this.headers.failureHeaders[`Forward-${WORKFLOW_FAILURE_CALLBACK_HEADER}`] = "true";
|
|
1836
1756
|
this.headers.failureHeaders["Workflow-Runid"] = this.workflowConfig.workflowRunId;
|
|
1837
1757
|
this.headers.failureHeaders["Workflow-Init"] = "false";
|
|
1838
1758
|
this.headers.failureHeaders["Workflow-Url"] = this.workflowConfig.workflowUrl;
|
|
1839
1759
|
this.headers.failureHeaders["Workflow-Calltype"] = "failureCall";
|
|
1840
|
-
this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody,WF_DetectTrigger";
|
|
1760
|
+
this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig";
|
|
1841
1761
|
if (this.workflowConfig.retries !== void 0 && this.workflowConfig.retries !== DEFAULT_RETRIES) {
|
|
1842
1762
|
this.headers.failureHeaders["Retries"] = this.workflowConfig.retries.toString();
|
|
1843
1763
|
}
|
|
@@ -1907,14 +1827,13 @@ var submitParallelSteps = async ({
|
|
|
1907
1827
|
initialStepCount,
|
|
1908
1828
|
invokeCount,
|
|
1909
1829
|
telemetry: telemetry2,
|
|
1910
|
-
|
|
1830
|
+
dispatchDebug
|
|
1911
1831
|
}) => {
|
|
1912
1832
|
const planSteps = steps.map(
|
|
1913
1833
|
(step, index) => step.getPlanStep(steps.length, initialStepCount + index)
|
|
1914
1834
|
);
|
|
1915
|
-
await
|
|
1916
|
-
|
|
1917
|
-
steps: planSteps
|
|
1835
|
+
await dispatchDebug("onInfo", {
|
|
1836
|
+
info: `Submitting ${planSteps.length} parallel steps.`
|
|
1918
1837
|
});
|
|
1919
1838
|
const result = await context.qstashClient.batch(
|
|
1920
1839
|
planSteps.map((planStep) => {
|
|
@@ -1923,10 +1842,6 @@ var submitParallelSteps = async ({
|
|
|
1923
1842
|
workflowConfig: {
|
|
1924
1843
|
workflowRunId: context.workflowRunId,
|
|
1925
1844
|
workflowUrl: context.url,
|
|
1926
|
-
failureUrl: context.failureUrl,
|
|
1927
|
-
retries: context.retries,
|
|
1928
|
-
retryDelay: context.retryDelay,
|
|
1929
|
-
flowControl: context.flowControl,
|
|
1930
1845
|
telemetry: telemetry2
|
|
1931
1846
|
},
|
|
1932
1847
|
userHeaders: context.headers,
|
|
@@ -1942,13 +1857,11 @@ var submitParallelSteps = async ({
|
|
|
1942
1857
|
};
|
|
1943
1858
|
})
|
|
1944
1859
|
);
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
})
|
|
1951
|
-
});
|
|
1860
|
+
if (result && result.length > 0) {
|
|
1861
|
+
await dispatchDebug("onInfo", {
|
|
1862
|
+
info: `Submitted ${planSteps.length} parallel steps. messageIds: ${result.filter((r) => r).map((r) => r.messageId).join(", ")}.`
|
|
1863
|
+
});
|
|
1864
|
+
}
|
|
1952
1865
|
throw new WorkflowAbort(planSteps[0].stepName, planSteps[0]);
|
|
1953
1866
|
};
|
|
1954
1867
|
var submitSingleStep = async ({
|
|
@@ -1958,14 +1871,13 @@ var submitSingleStep = async ({
|
|
|
1958
1871
|
invokeCount,
|
|
1959
1872
|
concurrency,
|
|
1960
1873
|
telemetry: telemetry2,
|
|
1961
|
-
|
|
1874
|
+
dispatchDebug,
|
|
1875
|
+
dispatchLifecycle
|
|
1962
1876
|
}) => {
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
fromRequest: false,
|
|
1966
|
-
step: resultStep,
|
|
1967
|
-
stepCount: stepId
|
|
1877
|
+
await dispatchLifecycle("beforeExecution", {
|
|
1878
|
+
stepName: lazyStep.stepName
|
|
1968
1879
|
});
|
|
1880
|
+
const resultStep = await lazyStep.getResultStep(concurrency, stepId);
|
|
1969
1881
|
const { headers } = lazyStep.getHeaders({
|
|
1970
1882
|
context,
|
|
1971
1883
|
step: resultStep,
|
|
@@ -1979,10 +1891,6 @@ var submitSingleStep = async ({
|
|
|
1979
1891
|
invokeCount,
|
|
1980
1892
|
telemetry: telemetry2
|
|
1981
1893
|
});
|
|
1982
|
-
await debug?.log("SUBMIT", "SUBMIT_STEP", {
|
|
1983
|
-
length: 1,
|
|
1984
|
-
steps: [resultStep]
|
|
1985
|
-
});
|
|
1986
1894
|
const submitResult = await lazyStep.submitStep({
|
|
1987
1895
|
context,
|
|
1988
1896
|
body,
|
|
@@ -1992,13 +1900,11 @@ var submitSingleStep = async ({
|
|
|
1992
1900
|
step: resultStep,
|
|
1993
1901
|
telemetry: telemetry2
|
|
1994
1902
|
});
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
})
|
|
2001
|
-
});
|
|
1903
|
+
if (submitResult && submitResult[0]) {
|
|
1904
|
+
await dispatchDebug("onInfo", {
|
|
1905
|
+
info: `Submitted step "${resultStep.stepName}" with messageId: ${submitResult[0].messageId}.`
|
|
1906
|
+
});
|
|
1907
|
+
}
|
|
2002
1908
|
return resultStep;
|
|
2003
1909
|
};
|
|
2004
1910
|
|
|
@@ -2007,21 +1913,31 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2007
1913
|
context;
|
|
2008
1914
|
promises = /* @__PURE__ */ new WeakMap();
|
|
2009
1915
|
activeLazyStepList;
|
|
2010
|
-
debug;
|
|
2011
1916
|
nonPlanStepCount;
|
|
2012
1917
|
steps;
|
|
2013
1918
|
indexInCurrentList = 0;
|
|
2014
1919
|
invokeCount;
|
|
2015
1920
|
telemetry;
|
|
1921
|
+
dispatchDebug;
|
|
1922
|
+
dispatchLifecycle;
|
|
2016
1923
|
stepCount = 0;
|
|
2017
1924
|
planStepCount = 0;
|
|
2018
1925
|
executingStep = false;
|
|
2019
|
-
|
|
1926
|
+
/**
|
|
1927
|
+
* @param context workflow context
|
|
1928
|
+
* @param steps list of steps
|
|
1929
|
+
* @param dispatchDebug debug event dispatcher
|
|
1930
|
+
* @param dispatchLifecycle lifecycle event dispatcher
|
|
1931
|
+
* @param telemetry optional telemetry information
|
|
1932
|
+
* @param invokeCount optional invoke count
|
|
1933
|
+
*/
|
|
1934
|
+
constructor(context, steps, dispatchDebug, dispatchLifecycle, telemetry2, invokeCount) {
|
|
2020
1935
|
this.context = context;
|
|
2021
1936
|
this.steps = steps;
|
|
1937
|
+
this.dispatchDebug = dispatchDebug;
|
|
1938
|
+
this.dispatchLifecycle = dispatchLifecycle;
|
|
2022
1939
|
this.telemetry = telemetry2;
|
|
2023
1940
|
this.invokeCount = invokeCount ?? 0;
|
|
2024
|
-
this.debug = debug;
|
|
2025
1941
|
this.nonPlanStepCount = this.steps.filter((step) => !step.targetStep).length;
|
|
2026
1942
|
}
|
|
2027
1943
|
/**
|
|
@@ -2089,7 +2005,7 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2089
2005
|
/**
|
|
2090
2006
|
* Executes a step:
|
|
2091
2007
|
* - If the step result is available in the steps, returns the result
|
|
2092
|
-
* - If the result is not
|
|
2008
|
+
* - If the result is not available, runs the function
|
|
2093
2009
|
* - Sends the result to QStash
|
|
2094
2010
|
*
|
|
2095
2011
|
* @param lazyStep lazy step to execute
|
|
@@ -2099,12 +2015,15 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2099
2015
|
if (this.stepCount < this.nonPlanStepCount) {
|
|
2100
2016
|
const step = this.steps[this.stepCount + this.planStepCount];
|
|
2101
2017
|
validateStep(lazyStep, step);
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2018
|
+
const parsedOut = lazyStep.parseOut(step);
|
|
2019
|
+
const isLastMemoized = this.stepCount + 1 === this.nonPlanStepCount && this.steps.at(-1).stepId !== 0;
|
|
2020
|
+
if (isLastMemoized) {
|
|
2021
|
+
await this.dispatchLifecycle("afterExecution", {
|
|
2022
|
+
stepName: lazyStep.stepName,
|
|
2023
|
+
result: parsedOut
|
|
2024
|
+
});
|
|
2025
|
+
}
|
|
2026
|
+
return parsedOut;
|
|
2108
2027
|
}
|
|
2109
2028
|
const resultStep = await submitSingleStep({
|
|
2110
2029
|
context: this.context,
|
|
@@ -2113,15 +2032,15 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2113
2032
|
invokeCount: this.invokeCount,
|
|
2114
2033
|
concurrency: 1,
|
|
2115
2034
|
telemetry: this.telemetry,
|
|
2116
|
-
|
|
2035
|
+
dispatchDebug: this.dispatchDebug,
|
|
2036
|
+
dispatchLifecycle: this.dispatchLifecycle
|
|
2117
2037
|
});
|
|
2118
2038
|
throw new WorkflowAbort(lazyStep.stepName, resultStep);
|
|
2119
2039
|
}
|
|
2120
2040
|
/**
|
|
2121
2041
|
* Runs steps in parallel.
|
|
2122
2042
|
*
|
|
2123
|
-
* @param
|
|
2124
|
-
* @param stepFunctions list of async functions to run in parallel
|
|
2043
|
+
* @param parallelSteps list of lazy steps to run in parallel
|
|
2125
2044
|
* @returns results of the functions run in parallel
|
|
2126
2045
|
*/
|
|
2127
2046
|
async runParallel(parallelSteps) {
|
|
@@ -2134,12 +2053,14 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2134
2053
|
`Incompatible number of parallel steps when call state was '${parallelCallState}'. Expected ${parallelSteps.length}, got ${plannedParallelStepCount} from the request.`
|
|
2135
2054
|
);
|
|
2136
2055
|
}
|
|
2137
|
-
await this.
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2056
|
+
await this.dispatchDebug("onInfo", {
|
|
2057
|
+
info: `Executing parallel steps with: ` + JSON.stringify({
|
|
2058
|
+
parallelCallState,
|
|
2059
|
+
initialStepCount,
|
|
2060
|
+
plannedParallelStepCount,
|
|
2061
|
+
stepCount: this.stepCount,
|
|
2062
|
+
planStepCount: this.planStepCount
|
|
2063
|
+
})
|
|
2143
2064
|
});
|
|
2144
2065
|
switch (parallelCallState) {
|
|
2145
2066
|
case "first": {
|
|
@@ -2149,7 +2070,7 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2149
2070
|
initialStepCount,
|
|
2150
2071
|
invokeCount: this.invokeCount,
|
|
2151
2072
|
telemetry: this.telemetry,
|
|
2152
|
-
|
|
2073
|
+
dispatchDebug: this.dispatchDebug
|
|
2153
2074
|
});
|
|
2154
2075
|
break;
|
|
2155
2076
|
}
|
|
@@ -2171,7 +2092,8 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2171
2092
|
invokeCount: this.invokeCount,
|
|
2172
2093
|
concurrency: parallelSteps.length,
|
|
2173
2094
|
telemetry: this.telemetry,
|
|
2174
|
-
|
|
2095
|
+
dispatchDebug: this.dispatchDebug,
|
|
2096
|
+
dispatchLifecycle: this.dispatchLifecycle
|
|
2175
2097
|
});
|
|
2176
2098
|
throw new WorkflowAbort(parallelStep.stepName, resultStep);
|
|
2177
2099
|
} catch (error) {
|
|
@@ -2185,11 +2107,32 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2185
2107
|
break;
|
|
2186
2108
|
}
|
|
2187
2109
|
case "discard": {
|
|
2110
|
+
const resultStep = this.steps.at(-1);
|
|
2111
|
+
const lazyStep = parallelSteps.find(
|
|
2112
|
+
(planStep, index) => resultStep.stepId - index === initialStepCount
|
|
2113
|
+
);
|
|
2114
|
+
if (lazyStep) {
|
|
2115
|
+
await this.dispatchLifecycle("afterExecution", {
|
|
2116
|
+
stepName: lazyStep.stepName,
|
|
2117
|
+
result: lazyStep.parseOut(resultStep)
|
|
2118
|
+
});
|
|
2119
|
+
}
|
|
2188
2120
|
throw new WorkflowAbort("discarded parallel");
|
|
2189
2121
|
}
|
|
2190
2122
|
case "last": {
|
|
2191
2123
|
const parallelResultSteps = sortedSteps.filter((step) => step.stepId >= initialStepCount).slice(0, parallelSteps.length);
|
|
2192
2124
|
validateParallelSteps(parallelSteps, parallelResultSteps);
|
|
2125
|
+
const isLastMemoized = this.stepCount + 1 === this.nonPlanStepCount && this.steps.at(-1).stepId !== 0;
|
|
2126
|
+
if (isLastMemoized) {
|
|
2127
|
+
const resultStep = this.steps.at(-1);
|
|
2128
|
+
const lazyStep = parallelSteps.find(
|
|
2129
|
+
(planStep, index) => resultStep.stepId - index === initialStepCount
|
|
2130
|
+
);
|
|
2131
|
+
await this.dispatchLifecycle("afterExecution", {
|
|
2132
|
+
stepName: lazyStep.stepName,
|
|
2133
|
+
result: lazyStep.parseOut(resultStep)
|
|
2134
|
+
});
|
|
2135
|
+
}
|
|
2193
2136
|
return parallelResultSteps.map(
|
|
2194
2137
|
(step, index) => parallelSteps[index].parseOut(step)
|
|
2195
2138
|
);
|
|
@@ -2333,15 +2276,18 @@ var getProviderInfo = (api) => {
|
|
|
2333
2276
|
// src/context/api/base.ts
|
|
2334
2277
|
var BaseWorkflowApi = class {
|
|
2335
2278
|
context;
|
|
2279
|
+
/**
|
|
2280
|
+
* @param context workflow context
|
|
2281
|
+
*/
|
|
2336
2282
|
constructor({ context }) {
|
|
2337
2283
|
this.context = context;
|
|
2338
2284
|
}
|
|
2339
2285
|
/**
|
|
2340
2286
|
* context.call which uses a QStash API
|
|
2341
2287
|
*
|
|
2342
|
-
* @param stepName
|
|
2343
|
-
* @param settings
|
|
2344
|
-
* @returns
|
|
2288
|
+
* @param stepName name of the step
|
|
2289
|
+
* @param settings call settings including api configuration
|
|
2290
|
+
* @returns call response
|
|
2345
2291
|
*/
|
|
2346
2292
|
async callApi(stepName, settings) {
|
|
2347
2293
|
const { url, appendHeaders, method } = getProviderInfo(settings.api);
|
|
@@ -2349,7 +2295,7 @@ var BaseWorkflowApi = class {
|
|
|
2349
2295
|
return await this.context.call(stepName, {
|
|
2350
2296
|
url,
|
|
2351
2297
|
method: userMethod ?? method,
|
|
2352
|
-
body,
|
|
2298
|
+
body: typeof body === "string" ? body : JSON.stringify(body),
|
|
2353
2299
|
headers: {
|
|
2354
2300
|
...appendHeaders,
|
|
2355
2301
|
...headers
|
|
@@ -2426,309 +2372,6 @@ var WorkflowApi = class extends BaseWorkflowApi {
|
|
|
2426
2372
|
}
|
|
2427
2373
|
};
|
|
2428
2374
|
|
|
2429
|
-
// src/agents/index.ts
|
|
2430
|
-
var import_openai2 = require("@ai-sdk/openai");
|
|
2431
|
-
|
|
2432
|
-
// src/agents/adapters.ts
|
|
2433
|
-
var import_ai = require("ai");
|
|
2434
|
-
var fetchWithContextCall = async (context, agentCallParams, ...params) => {
|
|
2435
|
-
const [input, init] = params;
|
|
2436
|
-
try {
|
|
2437
|
-
const headers = init?.headers ? Object.fromEntries(new Headers(init.headers).entries()) : {};
|
|
2438
|
-
const body = init?.body ? JSON.parse(init.body) : void 0;
|
|
2439
|
-
const agentName = headers[AGENT_NAME_HEADER];
|
|
2440
|
-
const stepName = agentName ? `Call Agent ${agentName}` : "Call Agent";
|
|
2441
|
-
const responseInfo = await context.call(stepName, {
|
|
2442
|
-
url: input.toString(),
|
|
2443
|
-
method: init?.method,
|
|
2444
|
-
headers,
|
|
2445
|
-
body,
|
|
2446
|
-
timeout: agentCallParams?.timeout,
|
|
2447
|
-
retries: agentCallParams?.retries,
|
|
2448
|
-
retryDelay: agentCallParams?.retryDelay,
|
|
2449
|
-
flowControl: agentCallParams?.flowControl
|
|
2450
|
-
});
|
|
2451
|
-
const responseHeaders = new Headers(
|
|
2452
|
-
Object.entries(responseInfo.header).reduce(
|
|
2453
|
-
(acc, [key, values]) => {
|
|
2454
|
-
acc[key] = values.join(", ");
|
|
2455
|
-
return acc;
|
|
2456
|
-
},
|
|
2457
|
-
{}
|
|
2458
|
-
)
|
|
2459
|
-
);
|
|
2460
|
-
return new Response(JSON.stringify(responseInfo.body), {
|
|
2461
|
-
status: responseInfo.status,
|
|
2462
|
-
headers: responseHeaders
|
|
2463
|
-
});
|
|
2464
|
-
} catch (error) {
|
|
2465
|
-
if (error instanceof Error && isInstanceOf(error, WorkflowAbort)) {
|
|
2466
|
-
throw error;
|
|
2467
|
-
} else {
|
|
2468
|
-
console.error("Error in fetch implementation:", error);
|
|
2469
|
-
throw error;
|
|
2470
|
-
}
|
|
2471
|
-
}
|
|
2472
|
-
};
|
|
2473
|
-
var createWorkflowModel = ({
|
|
2474
|
-
context,
|
|
2475
|
-
provider,
|
|
2476
|
-
providerParams,
|
|
2477
|
-
agentCallParams
|
|
2478
|
-
}) => {
|
|
2479
|
-
return provider({
|
|
2480
|
-
fetch: (...params) => fetchWithContextCall(context, agentCallParams, ...params),
|
|
2481
|
-
...providerParams
|
|
2482
|
-
});
|
|
2483
|
-
};
|
|
2484
|
-
var wrapTools = ({
|
|
2485
|
-
context,
|
|
2486
|
-
tools
|
|
2487
|
-
}) => {
|
|
2488
|
-
return Object.fromEntries(
|
|
2489
|
-
Object.entries(tools).map((toolInfo) => {
|
|
2490
|
-
const [toolName, tool3] = toolInfo;
|
|
2491
|
-
const executeAsStep = "executeAsStep" in tool3 ? tool3.executeAsStep : true;
|
|
2492
|
-
const aiSDKTool = convertToAISDKTool(tool3);
|
|
2493
|
-
const execute = aiSDKTool.execute;
|
|
2494
|
-
if (execute && executeAsStep) {
|
|
2495
|
-
const wrappedExecute = (...params) => {
|
|
2496
|
-
return context.run(`Run tool ${toolName}`, () => execute(...params));
|
|
2497
|
-
};
|
|
2498
|
-
aiSDKTool.execute = wrappedExecute;
|
|
2499
|
-
}
|
|
2500
|
-
return [toolName, aiSDKTool];
|
|
2501
|
-
})
|
|
2502
|
-
);
|
|
2503
|
-
};
|
|
2504
|
-
var convertToAISDKTool = (tool3) => {
|
|
2505
|
-
const isLangchainTool = "invoke" in tool3;
|
|
2506
|
-
return isLangchainTool ? convertLangchainTool(tool3) : tool3;
|
|
2507
|
-
};
|
|
2508
|
-
var convertLangchainTool = (langchainTool) => {
|
|
2509
|
-
return (0, import_ai.tool)({
|
|
2510
|
-
description: langchainTool.description,
|
|
2511
|
-
parameters: langchainTool.schema,
|
|
2512
|
-
execute: async (...param) => langchainTool.invoke(...param)
|
|
2513
|
-
});
|
|
2514
|
-
};
|
|
2515
|
-
|
|
2516
|
-
// src/agents/agent.ts
|
|
2517
|
-
var import_zod = require("zod");
|
|
2518
|
-
var import_ai2 = require("ai");
|
|
2519
|
-
|
|
2520
|
-
// src/serve/utils.ts
|
|
2521
|
-
var isDisabledWorkflowContext = (context) => {
|
|
2522
|
-
return "disabled" in context;
|
|
2523
|
-
};
|
|
2524
|
-
|
|
2525
|
-
// src/agents/agent.ts
|
|
2526
|
-
var Agent = class {
|
|
2527
|
-
name;
|
|
2528
|
-
tools;
|
|
2529
|
-
maxSteps;
|
|
2530
|
-
background;
|
|
2531
|
-
model;
|
|
2532
|
-
temparature;
|
|
2533
|
-
context;
|
|
2534
|
-
constructor({ tools, maxSteps, background, name, model, temparature = 0.1 }, context) {
|
|
2535
|
-
this.name = name;
|
|
2536
|
-
this.tools = tools ?? {};
|
|
2537
|
-
this.maxSteps = maxSteps;
|
|
2538
|
-
this.background = background;
|
|
2539
|
-
this.model = model;
|
|
2540
|
-
this.temparature = temparature;
|
|
2541
|
-
this.context = context;
|
|
2542
|
-
}
|
|
2543
|
-
/**
|
|
2544
|
-
* Trigger the agent by passing a prompt
|
|
2545
|
-
*
|
|
2546
|
-
* @param prompt task to assign to the agent
|
|
2547
|
-
* @returns Response as `{ text: string }`
|
|
2548
|
-
*/
|
|
2549
|
-
async call({ prompt }) {
|
|
2550
|
-
try {
|
|
2551
|
-
if (isDisabledWorkflowContext(this.context)) {
|
|
2552
|
-
await this.context.sleep("abort", 0);
|
|
2553
|
-
}
|
|
2554
|
-
const result = await (0, import_ai2.generateText)({
|
|
2555
|
-
model: this.model,
|
|
2556
|
-
tools: this.tools,
|
|
2557
|
-
maxSteps: this.maxSteps,
|
|
2558
|
-
system: this.background,
|
|
2559
|
-
prompt,
|
|
2560
|
-
headers: {
|
|
2561
|
-
[AGENT_NAME_HEADER]: this.name
|
|
2562
|
-
},
|
|
2563
|
-
temperature: this.temparature
|
|
2564
|
-
});
|
|
2565
|
-
return { text: result.text };
|
|
2566
|
-
} catch (error) {
|
|
2567
|
-
if (isInstanceOf(error, import_ai2.ToolExecutionError)) {
|
|
2568
|
-
if (error.cause instanceof Error && isInstanceOf(error.cause, WorkflowAbort)) {
|
|
2569
|
-
throw error.cause;
|
|
2570
|
-
} else if (isInstanceOf(error.cause, import_ai2.ToolExecutionError) && isInstanceOf(error.cause.cause, WorkflowAbort)) {
|
|
2571
|
-
throw error.cause.cause;
|
|
2572
|
-
} else {
|
|
2573
|
-
throw error;
|
|
2574
|
-
}
|
|
2575
|
-
} else {
|
|
2576
|
-
throw error;
|
|
2577
|
-
}
|
|
2578
|
-
}
|
|
2579
|
-
}
|
|
2580
|
-
/**
|
|
2581
|
-
* Convert the agent to a tool which can be used by other agents.
|
|
2582
|
-
*
|
|
2583
|
-
* @returns the agent as a tool
|
|
2584
|
-
*/
|
|
2585
|
-
asTool() {
|
|
2586
|
-
const toolDescriptions = Object.values(this.tools).map((tool3) => tool3.description).join("\n");
|
|
2587
|
-
return (0, import_ai2.tool)({
|
|
2588
|
-
parameters: import_zod.z.object({ prompt: import_zod.z.string() }),
|
|
2589
|
-
execute: async ({ prompt }) => {
|
|
2590
|
-
return await this.call({ prompt });
|
|
2591
|
-
},
|
|
2592
|
-
description: `An AI Agent with the following background: ${this.background}Has access to the following tools: ${toolDescriptions}`
|
|
2593
|
-
});
|
|
2594
|
-
}
|
|
2595
|
-
};
|
|
2596
|
-
var ManagerAgent = class extends Agent {
|
|
2597
|
-
agents;
|
|
2598
|
-
/**
|
|
2599
|
-
* A manager agent which coordinates agents available to it to achieve a
|
|
2600
|
-
* given task
|
|
2601
|
-
*
|
|
2602
|
-
* @param name Name of the agent
|
|
2603
|
-
* @param background Background of the agent. If not passed, default will be used.
|
|
2604
|
-
* @param model LLM model to use
|
|
2605
|
-
* @param agents: List of agents available to the agent
|
|
2606
|
-
* @param maxSteps number of times the manager agent can call the LLM at most.
|
|
2607
|
-
* If the agent abruptly stops execution after calling other agents, you may
|
|
2608
|
-
* need to increase maxSteps
|
|
2609
|
-
*/
|
|
2610
|
-
constructor({
|
|
2611
|
-
agents,
|
|
2612
|
-
background = MANAGER_AGENT_PROMPT,
|
|
2613
|
-
model,
|
|
2614
|
-
maxSteps,
|
|
2615
|
-
name = "manager llm"
|
|
2616
|
-
}, context) {
|
|
2617
|
-
super(
|
|
2618
|
-
{
|
|
2619
|
-
background,
|
|
2620
|
-
maxSteps,
|
|
2621
|
-
tools: Object.fromEntries(agents.map((agent) => [agent.name, agent.asTool()])),
|
|
2622
|
-
name,
|
|
2623
|
-
model
|
|
2624
|
-
},
|
|
2625
|
-
context
|
|
2626
|
-
);
|
|
2627
|
-
this.agents = agents;
|
|
2628
|
-
}
|
|
2629
|
-
};
|
|
2630
|
-
|
|
2631
|
-
// src/agents/task.ts
|
|
2632
|
-
var Task = class {
|
|
2633
|
-
context;
|
|
2634
|
-
taskParameters;
|
|
2635
|
-
constructor({
|
|
2636
|
-
context,
|
|
2637
|
-
taskParameters
|
|
2638
|
-
}) {
|
|
2639
|
-
this.context = context;
|
|
2640
|
-
this.taskParameters = taskParameters;
|
|
2641
|
-
}
|
|
2642
|
-
/**
|
|
2643
|
-
* Run the agents to complete the task
|
|
2644
|
-
*
|
|
2645
|
-
* @returns Result of the task as { text: string }
|
|
2646
|
-
*/
|
|
2647
|
-
async run() {
|
|
2648
|
-
const { prompt, ...otherParams } = this.taskParameters;
|
|
2649
|
-
if ("agent" in otherParams) {
|
|
2650
|
-
const agent = otherParams.agent;
|
|
2651
|
-
const result = await agent.call({
|
|
2652
|
-
prompt
|
|
2653
|
-
});
|
|
2654
|
-
return { text: result.text };
|
|
2655
|
-
} else {
|
|
2656
|
-
const { agents, maxSteps, model, background } = otherParams;
|
|
2657
|
-
const managerAgent = new ManagerAgent(
|
|
2658
|
-
{
|
|
2659
|
-
model,
|
|
2660
|
-
maxSteps,
|
|
2661
|
-
agents,
|
|
2662
|
-
name: "Manager LLM",
|
|
2663
|
-
background
|
|
2664
|
-
},
|
|
2665
|
-
this.context
|
|
2666
|
-
);
|
|
2667
|
-
const result = await managerAgent.call({ prompt });
|
|
2668
|
-
return { text: result.text };
|
|
2669
|
-
}
|
|
2670
|
-
}
|
|
2671
|
-
};
|
|
2672
|
-
|
|
2673
|
-
// src/agents/index.ts
|
|
2674
|
-
var WorkflowAgents = class {
|
|
2675
|
-
context;
|
|
2676
|
-
constructor({ context }) {
|
|
2677
|
-
this.context = context;
|
|
2678
|
-
}
|
|
2679
|
-
/**
|
|
2680
|
-
* Defines an agent
|
|
2681
|
-
*
|
|
2682
|
-
* ```ts
|
|
2683
|
-
* const researcherAgent = context.agents.agent({
|
|
2684
|
-
* model,
|
|
2685
|
-
* name: 'academic',
|
|
2686
|
-
* maxSteps: 2,
|
|
2687
|
-
* tools: {
|
|
2688
|
-
* wikiTool: new WikipediaQueryRun({
|
|
2689
|
-
* topKResults: 1,
|
|
2690
|
-
* maxDocContentLength: 500,
|
|
2691
|
-
* })
|
|
2692
|
-
* },
|
|
2693
|
-
* background:
|
|
2694
|
-
* 'You are researcher agent with access to Wikipedia. ' +
|
|
2695
|
-
* 'Utilize Wikipedia as much as possible for correct information',
|
|
2696
|
-
* });
|
|
2697
|
-
* ```
|
|
2698
|
-
*
|
|
2699
|
-
* @param params agent parameters
|
|
2700
|
-
* @returns
|
|
2701
|
-
*/
|
|
2702
|
-
agent(params) {
|
|
2703
|
-
const wrappedTools = wrapTools({ context: this.context, tools: params.tools });
|
|
2704
|
-
return new Agent(
|
|
2705
|
-
{
|
|
2706
|
-
...params,
|
|
2707
|
-
tools: wrappedTools
|
|
2708
|
-
},
|
|
2709
|
-
this.context
|
|
2710
|
-
);
|
|
2711
|
-
}
|
|
2712
|
-
task(taskParameters) {
|
|
2713
|
-
return new Task({ context: this.context, taskParameters });
|
|
2714
|
-
}
|
|
2715
|
-
/**
|
|
2716
|
-
* creates an openai model for agents
|
|
2717
|
-
*/
|
|
2718
|
-
openai(...params) {
|
|
2719
|
-
const [model, settings] = params;
|
|
2720
|
-
const { baseURL, apiKey, callSettings, ...otherSettings } = settings ?? {};
|
|
2721
|
-
const openaiModel = this.AISDKModel({
|
|
2722
|
-
context: this.context,
|
|
2723
|
-
provider: import_openai2.createOpenAI,
|
|
2724
|
-
providerParams: { baseURL, apiKey, compatibility: "strict" },
|
|
2725
|
-
agentCallParams: callSettings
|
|
2726
|
-
});
|
|
2727
|
-
return openaiModel(model, otherSettings);
|
|
2728
|
-
}
|
|
2729
|
-
AISDKModel = createWorkflowModel;
|
|
2730
|
-
};
|
|
2731
|
-
|
|
2732
2375
|
// src/serve/serve-many.ts
|
|
2733
2376
|
var getWorkflowId = (url) => {
|
|
2734
2377
|
const components = url.split("/");
|
|
@@ -2804,56 +2447,160 @@ var getNewUrlFromWorkflowId = (url, workflowId) => {
|
|
|
2804
2447
|
return url.replace(/[^/]+$/, workflowId);
|
|
2805
2448
|
};
|
|
2806
2449
|
|
|
2807
|
-
// src/
|
|
2808
|
-
var
|
|
2809
|
-
|
|
2810
|
-
|
|
2450
|
+
// src/middleware/default-callbacks.ts
|
|
2451
|
+
var onErrorWithConsole = async ({ workflowRunId, error }) => {
|
|
2452
|
+
console.error(` [Upstash Workflow]: Error in workflow run ${workflowRunId}: ` + error);
|
|
2453
|
+
};
|
|
2454
|
+
var onWarningWithConsole = async ({ workflowRunId, warning }) => {
|
|
2455
|
+
console.warn(` [Upstash Workflow]: Warning in workflow run ${workflowRunId}: ` + warning);
|
|
2456
|
+
};
|
|
2457
|
+
var onInfoWithConsole = async ({
|
|
2458
|
+
workflowRunId,
|
|
2459
|
+
info
|
|
2460
|
+
}) => {
|
|
2461
|
+
console.info(` [Upstash Workflow]: Info in workflow run ${workflowRunId}: ` + info);
|
|
2462
|
+
};
|
|
2463
|
+
|
|
2464
|
+
// src/middleware/manager.ts
|
|
2465
|
+
var MiddlewareManager = class {
|
|
2466
|
+
middlewares;
|
|
2467
|
+
workflowRunId;
|
|
2468
|
+
context;
|
|
2811
2469
|
/**
|
|
2812
|
-
*
|
|
2470
|
+
* @param middlewares list of workflow middlewares
|
|
2471
|
+
*/
|
|
2472
|
+
constructor(middlewares = []) {
|
|
2473
|
+
this.middlewares = middlewares;
|
|
2474
|
+
}
|
|
2475
|
+
/**
|
|
2476
|
+
* Assign workflow run ID - will be passed to debug events
|
|
2813
2477
|
*
|
|
2814
|
-
*
|
|
2478
|
+
* @param workflowRunId workflow run id to assign
|
|
2479
|
+
*/
|
|
2480
|
+
assignWorkflowRunId(workflowRunId) {
|
|
2481
|
+
this.workflowRunId = workflowRunId;
|
|
2482
|
+
}
|
|
2483
|
+
/**
|
|
2484
|
+
* Assign context - required for lifecycle events
|
|
2815
2485
|
*
|
|
2816
|
-
*
|
|
2817
|
-
* import { Client } from "@upstash/qstash"
|
|
2486
|
+
* also assigns workflowRunId from context
|
|
2818
2487
|
*
|
|
2819
|
-
*
|
|
2820
|
-
* async (context) => {
|
|
2821
|
-
* ...
|
|
2822
|
-
* },
|
|
2823
|
-
* {
|
|
2824
|
-
* qstashClient: new Client({...})
|
|
2825
|
-
* }
|
|
2826
|
-
* )
|
|
2827
|
-
* ```
|
|
2488
|
+
* @param context workflow context to assign
|
|
2828
2489
|
*/
|
|
2829
|
-
|
|
2490
|
+
assignContext(context) {
|
|
2491
|
+
this.context = context;
|
|
2492
|
+
this.workflowRunId = context.workflowRunId;
|
|
2493
|
+
}
|
|
2830
2494
|
/**
|
|
2831
|
-
*
|
|
2495
|
+
* Internal method to execute middlewares with common error handling logic
|
|
2496
|
+
*
|
|
2497
|
+
* @param event event name to dispatch
|
|
2498
|
+
* @param params event parameters
|
|
2832
2499
|
*/
|
|
2833
|
-
|
|
2500
|
+
async executeMiddlewares(event, params) {
|
|
2501
|
+
await Promise.all(this.middlewares.map((m) => m.ensureInit()));
|
|
2502
|
+
await Promise.all(
|
|
2503
|
+
this.middlewares.map(async (middleware) => {
|
|
2504
|
+
const callback = middleware.getCallback(event);
|
|
2505
|
+
if (callback) {
|
|
2506
|
+
try {
|
|
2507
|
+
await callback(params);
|
|
2508
|
+
} catch (error) {
|
|
2509
|
+
try {
|
|
2510
|
+
const onErrorCallback = middleware.getCallback("onError") ?? onErrorWithConsole;
|
|
2511
|
+
await onErrorCallback({
|
|
2512
|
+
workflowRunId: this.workflowRunId,
|
|
2513
|
+
error
|
|
2514
|
+
});
|
|
2515
|
+
} catch (onErrorError) {
|
|
2516
|
+
console.error(
|
|
2517
|
+
`Failed while executing "onError" of middleware "${middleware.name}", falling back to logging the error to console. Error: ${onErrorError}`
|
|
2518
|
+
);
|
|
2519
|
+
onErrorWithConsole({
|
|
2520
|
+
workflowRunId: this.workflowRunId,
|
|
2521
|
+
error
|
|
2522
|
+
});
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
})
|
|
2527
|
+
);
|
|
2528
|
+
if (event === "onError") {
|
|
2529
|
+
onErrorWithConsole({
|
|
2530
|
+
workflowRunId: this.workflowRunId,
|
|
2531
|
+
...params
|
|
2532
|
+
});
|
|
2533
|
+
} else if (event === "onWarning") {
|
|
2534
|
+
onWarningWithConsole({
|
|
2535
|
+
workflowRunId: this.workflowRunId,
|
|
2536
|
+
...params
|
|
2537
|
+
});
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2834
2540
|
/**
|
|
2835
|
-
*
|
|
2541
|
+
* Dispatch a debug event (onError, onWarning, onInfo)
|
|
2836
2542
|
*
|
|
2837
|
-
*
|
|
2543
|
+
* @param event debug event name
|
|
2544
|
+
* @param params event parameters
|
|
2545
|
+
*/
|
|
2546
|
+
async dispatchDebug(event, params) {
|
|
2547
|
+
const paramsWithRunId = {
|
|
2548
|
+
...params,
|
|
2549
|
+
workflowRunId: this.workflowRunId
|
|
2550
|
+
};
|
|
2551
|
+
await this.executeMiddlewares(event, paramsWithRunId);
|
|
2552
|
+
}
|
|
2553
|
+
/**
|
|
2554
|
+
* Dispatch a lifecycle event (beforeExecution, afterExecution, runStarted, runCompleted)
|
|
2555
|
+
*
|
|
2556
|
+
* @param event lifecycle event name
|
|
2557
|
+
* @param params event parameters
|
|
2558
|
+
*/
|
|
2559
|
+
async dispatchLifecycle(event, params) {
|
|
2560
|
+
if (!this.context) {
|
|
2561
|
+
throw new WorkflowError(
|
|
2562
|
+
`Something went wrong while calling middlewares. Lifecycle event "${event}" was called before assignContext.`
|
|
2563
|
+
);
|
|
2564
|
+
}
|
|
2565
|
+
const paramsWithContext = {
|
|
2566
|
+
...params,
|
|
2567
|
+
context: this.context
|
|
2568
|
+
};
|
|
2569
|
+
await this.executeMiddlewares(event, paramsWithContext);
|
|
2570
|
+
}
|
|
2571
|
+
};
|
|
2572
|
+
|
|
2573
|
+
// src/context/context.ts
|
|
2574
|
+
var WorkflowContext = class {
|
|
2575
|
+
executor;
|
|
2576
|
+
steps;
|
|
2577
|
+
/**
|
|
2578
|
+
* QStash client of the workflow
|
|
2579
|
+
*
|
|
2580
|
+
* Can be overwritten by passing `qstashClient` parameter in `serve`:
|
|
2838
2581
|
*
|
|
2839
2582
|
* ```ts
|
|
2583
|
+
* import { Client } from "@upstash/qstash"
|
|
2584
|
+
*
|
|
2840
2585
|
* export const POST = serve(
|
|
2841
2586
|
* async (context) => {
|
|
2842
2587
|
* ...
|
|
2843
2588
|
* },
|
|
2844
2589
|
* {
|
|
2845
|
-
*
|
|
2590
|
+
* qstashClient: new Client({...})
|
|
2846
2591
|
* }
|
|
2847
2592
|
* )
|
|
2848
2593
|
* ```
|
|
2849
2594
|
*/
|
|
2850
|
-
|
|
2595
|
+
qstashClient;
|
|
2851
2596
|
/**
|
|
2852
|
-
*
|
|
2853
|
-
|
|
2854
|
-
|
|
2597
|
+
* Run id of the workflow
|
|
2598
|
+
*/
|
|
2599
|
+
workflowRunId;
|
|
2600
|
+
/**
|
|
2601
|
+
* URL of the workflow
|
|
2855
2602
|
*
|
|
2856
|
-
* Can be overwritten by passing a `
|
|
2603
|
+
* Can be overwritten by passing a `url` parameter in `serve`:
|
|
2857
2604
|
*
|
|
2858
2605
|
* ```ts
|
|
2859
2606
|
* export const POST = serve(
|
|
@@ -2861,12 +2608,12 @@ var WorkflowContext = class {
|
|
|
2861
2608
|
* ...
|
|
2862
2609
|
* },
|
|
2863
2610
|
* {
|
|
2864
|
-
*
|
|
2611
|
+
* url: "new-url-value"
|
|
2865
2612
|
* }
|
|
2866
2613
|
* )
|
|
2867
2614
|
* ```
|
|
2868
2615
|
*/
|
|
2869
|
-
|
|
2616
|
+
url;
|
|
2870
2617
|
/**
|
|
2871
2618
|
* Payload of the request which started the workflow.
|
|
2872
2619
|
*
|
|
@@ -2922,46 +2669,6 @@ var WorkflowContext = class {
|
|
|
2922
2669
|
* Default value is set to `process.env`.
|
|
2923
2670
|
*/
|
|
2924
2671
|
env;
|
|
2925
|
-
/**
|
|
2926
|
-
* Number of retries
|
|
2927
|
-
*/
|
|
2928
|
-
retries;
|
|
2929
|
-
/**
|
|
2930
|
-
* Delay between retries.
|
|
2931
|
-
*
|
|
2932
|
-
* By default, the `retryDelay` is exponential backoff.
|
|
2933
|
-
* More details can be found in: https://upstash.com/docs/qstash/features/retry.
|
|
2934
|
-
*
|
|
2935
|
-
* The `retryDelay` option allows you to customize the delay (in milliseconds) between retry attempts when message delivery fails.
|
|
2936
|
-
*
|
|
2937
|
-
* You can use mathematical expressions and the following built-in functions to calculate the delay dynamically.
|
|
2938
|
-
* The special variable `retried` represents the current retry attempt count (starting from 0).
|
|
2939
|
-
*
|
|
2940
|
-
* Supported functions:
|
|
2941
|
-
* - `pow`
|
|
2942
|
-
* - `sqrt`
|
|
2943
|
-
* - `abs`
|
|
2944
|
-
* - `exp`
|
|
2945
|
-
* - `floor`
|
|
2946
|
-
* - `ceil`
|
|
2947
|
-
* - `round`
|
|
2948
|
-
* - `min`
|
|
2949
|
-
* - `max`
|
|
2950
|
-
*
|
|
2951
|
-
* Examples of valid `retryDelay` values:
|
|
2952
|
-
* ```ts
|
|
2953
|
-
* 1000 // 1 second
|
|
2954
|
-
* 1000 * (1 + retried) // 1 second multiplied by the current retry attempt
|
|
2955
|
-
* pow(2, retried) // 2 to the power of the current retry attempt
|
|
2956
|
-
* max(10, pow(2, retried)) // The greater of 10 or 2^retried
|
|
2957
|
-
* ```
|
|
2958
|
-
*/
|
|
2959
|
-
retryDelay;
|
|
2960
|
-
/**
|
|
2961
|
-
* Settings for controlling the number of active requests
|
|
2962
|
-
* and number of requests per second with the same key.
|
|
2963
|
-
*/
|
|
2964
|
-
flowControl;
|
|
2965
2672
|
/**
|
|
2966
2673
|
* Label to apply to the workflow run.
|
|
2967
2674
|
*
|
|
@@ -2984,30 +2691,31 @@ var WorkflowContext = class {
|
|
|
2984
2691
|
headers,
|
|
2985
2692
|
steps,
|
|
2986
2693
|
url,
|
|
2987
|
-
failureUrl,
|
|
2988
|
-
debug,
|
|
2989
2694
|
initialPayload,
|
|
2990
2695
|
env,
|
|
2991
|
-
retries,
|
|
2992
|
-
retryDelay,
|
|
2993
2696
|
telemetry: telemetry2,
|
|
2994
2697
|
invokeCount,
|
|
2995
|
-
|
|
2996
|
-
|
|
2698
|
+
label,
|
|
2699
|
+
middlewareManager
|
|
2997
2700
|
}) {
|
|
2998
2701
|
this.qstashClient = qstashClient;
|
|
2999
2702
|
this.workflowRunId = workflowRunId;
|
|
3000
2703
|
this.steps = steps;
|
|
3001
2704
|
this.url = url;
|
|
3002
|
-
this.failureUrl = failureUrl;
|
|
3003
2705
|
this.headers = headers;
|
|
3004
2706
|
this.requestPayload = initialPayload;
|
|
3005
2707
|
this.env = env ?? {};
|
|
3006
|
-
this.retries = retries ?? DEFAULT_RETRIES;
|
|
3007
|
-
this.retryDelay = retryDelay;
|
|
3008
|
-
this.flowControl = flowControl;
|
|
3009
2708
|
this.label = label;
|
|
3010
|
-
|
|
2709
|
+
const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
|
|
2710
|
+
middlewareManagerInstance.assignContext(this);
|
|
2711
|
+
this.executor = new AutoExecutor(
|
|
2712
|
+
this,
|
|
2713
|
+
this.steps,
|
|
2714
|
+
middlewareManagerInstance.dispatchDebug.bind(middlewareManagerInstance),
|
|
2715
|
+
middlewareManagerInstance.dispatchLifecycle.bind(middlewareManagerInstance),
|
|
2716
|
+
telemetry2,
|
|
2717
|
+
invokeCount
|
|
2718
|
+
);
|
|
3011
2719
|
}
|
|
3012
2720
|
/**
|
|
3013
2721
|
* Executes a workflow step
|
|
@@ -3037,7 +2745,7 @@ var WorkflowContext = class {
|
|
|
3037
2745
|
* @returns result of the step function
|
|
3038
2746
|
*/
|
|
3039
2747
|
async run(stepName, stepFunction) {
|
|
3040
|
-
const wrappedStepFunction = () => this.executor.wrapStep(stepName, stepFunction);
|
|
2748
|
+
const wrappedStepFunction = (() => this.executor.wrapStep(stepName, stepFunction));
|
|
3041
2749
|
return await this.addStep(new LazyFunctionStep(this, stepName, wrappedStepFunction));
|
|
3042
2750
|
}
|
|
3043
2751
|
/**
|
|
@@ -3080,44 +2788,32 @@ var WorkflowContext = class {
|
|
|
3080
2788
|
let callStep;
|
|
3081
2789
|
if ("workflow" in settings) {
|
|
3082
2790
|
const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
|
|
3083
|
-
|
|
3084
|
-
|
|
2791
|
+
const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
|
|
2792
|
+
callStep = new LazyCallStep({
|
|
2793
|
+
context: this,
|
|
3085
2794
|
stepName,
|
|
3086
2795
|
url,
|
|
3087
|
-
"POST",
|
|
3088
|
-
|
|
3089
|
-
settings.headers || {},
|
|
3090
|
-
settings.retries || 0,
|
|
3091
|
-
settings.retryDelay,
|
|
3092
|
-
settings.timeout,
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
);
|
|
2796
|
+
method: "POST",
|
|
2797
|
+
body: stringBody,
|
|
2798
|
+
headers: settings.headers || {},
|
|
2799
|
+
retries: settings.retries || 0,
|
|
2800
|
+
retryDelay: settings.retryDelay,
|
|
2801
|
+
timeout: settings.timeout,
|
|
2802
|
+
flowControl: settings.flowControl
|
|
2803
|
+
});
|
|
3096
2804
|
} else {
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
method = "GET",
|
|
3100
|
-
body,
|
|
3101
|
-
headers = {},
|
|
3102
|
-
retries = 0,
|
|
3103
|
-
retryDelay,
|
|
3104
|
-
timeout,
|
|
3105
|
-
flowControl,
|
|
3106
|
-
stringifyBody = true
|
|
3107
|
-
} = settings;
|
|
3108
|
-
callStep = new LazyCallStep(
|
|
3109
|
-
this,
|
|
2805
|
+
callStep = new LazyCallStep({
|
|
2806
|
+
context: this,
|
|
3110
2807
|
stepName,
|
|
3111
|
-
url,
|
|
3112
|
-
method,
|
|
3113
|
-
body,
|
|
3114
|
-
headers,
|
|
3115
|
-
retries,
|
|
3116
|
-
retryDelay,
|
|
3117
|
-
timeout,
|
|
3118
|
-
flowControl
|
|
3119
|
-
|
|
3120
|
-
);
|
|
2808
|
+
url: settings.url,
|
|
2809
|
+
method: settings.method ?? "GET",
|
|
2810
|
+
body: settings.body,
|
|
2811
|
+
headers: settings.headers ?? {},
|
|
2812
|
+
retries: settings.retries ?? 0,
|
|
2813
|
+
retryDelay: settings.retryDelay,
|
|
2814
|
+
timeout: settings.timeout,
|
|
2815
|
+
flowControl: settings.flowControl
|
|
2816
|
+
});
|
|
3121
2817
|
}
|
|
3122
2818
|
return await this.addStep(callStep);
|
|
3123
2819
|
}
|
|
@@ -3202,11 +2898,11 @@ var WorkflowContext = class {
|
|
|
3202
2898
|
/**
|
|
3203
2899
|
* Cancel the current workflow run
|
|
3204
2900
|
*
|
|
3205
|
-
* Will throw
|
|
2901
|
+
* Will throw WorkflowCancelAbort to stop workflow execution.
|
|
3206
2902
|
* Shouldn't be inside try/catch.
|
|
3207
2903
|
*/
|
|
3208
2904
|
async cancel() {
|
|
3209
|
-
throw new
|
|
2905
|
+
throw new WorkflowCancelAbort();
|
|
3210
2906
|
}
|
|
3211
2907
|
/**
|
|
3212
2908
|
* Adds steps to the executor. Needed so that it can be overwritten in
|
|
@@ -3220,60 +2916,6 @@ var WorkflowContext = class {
|
|
|
3220
2916
|
context: this
|
|
3221
2917
|
});
|
|
3222
2918
|
}
|
|
3223
|
-
get agents() {
|
|
3224
|
-
return new WorkflowAgents({
|
|
3225
|
-
context: this
|
|
3226
|
-
});
|
|
3227
|
-
}
|
|
3228
|
-
};
|
|
3229
|
-
|
|
3230
|
-
// src/logger.ts
|
|
3231
|
-
var LOG_LEVELS = ["DEBUG", "INFO", "SUBMIT", "WARN", "ERROR"];
|
|
3232
|
-
var WorkflowLogger = class _WorkflowLogger {
|
|
3233
|
-
logs = [];
|
|
3234
|
-
options;
|
|
3235
|
-
workflowRunId = void 0;
|
|
3236
|
-
constructor(options) {
|
|
3237
|
-
this.options = options;
|
|
3238
|
-
}
|
|
3239
|
-
async log(level, eventType, details) {
|
|
3240
|
-
if (this.shouldLog(level)) {
|
|
3241
|
-
const timestamp = Date.now();
|
|
3242
|
-
const logEntry = {
|
|
3243
|
-
timestamp,
|
|
3244
|
-
workflowRunId: this.workflowRunId ?? "",
|
|
3245
|
-
logLevel: level,
|
|
3246
|
-
eventType,
|
|
3247
|
-
details
|
|
3248
|
-
};
|
|
3249
|
-
this.logs.push(logEntry);
|
|
3250
|
-
if (this.options.logOutput === "console") {
|
|
3251
|
-
this.writeToConsole(logEntry);
|
|
3252
|
-
}
|
|
3253
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
3254
|
-
}
|
|
3255
|
-
}
|
|
3256
|
-
setWorkflowRunId(workflowRunId) {
|
|
3257
|
-
this.workflowRunId = workflowRunId;
|
|
3258
|
-
}
|
|
3259
|
-
writeToConsole(logEntry) {
|
|
3260
|
-
const JSON_SPACING = 2;
|
|
3261
|
-
const logMethod = logEntry.logLevel === "ERROR" ? console.error : logEntry.logLevel === "WARN" ? console.warn : console.log;
|
|
3262
|
-
logMethod(JSON.stringify(logEntry, void 0, JSON_SPACING));
|
|
3263
|
-
}
|
|
3264
|
-
shouldLog(level) {
|
|
3265
|
-
return LOG_LEVELS.indexOf(level) >= LOG_LEVELS.indexOf(this.options.logLevel);
|
|
3266
|
-
}
|
|
3267
|
-
static getLogger(verbose) {
|
|
3268
|
-
if (typeof verbose === "object") {
|
|
3269
|
-
return verbose;
|
|
3270
|
-
} else {
|
|
3271
|
-
return verbose ? new _WorkflowLogger({
|
|
3272
|
-
logLevel: "INFO",
|
|
3273
|
-
logOutput: "console"
|
|
3274
|
-
}) : void 0;
|
|
3275
|
-
}
|
|
3276
|
-
}
|
|
3277
2919
|
};
|
|
3278
2920
|
|
|
3279
2921
|
// src/serve/authorization.ts
|
|
@@ -3282,19 +2924,19 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
|
|
|
3282
2924
|
static disabledMessage = "disabled-qstash-worklfow-run";
|
|
3283
2925
|
disabled = true;
|
|
3284
2926
|
/**
|
|
3285
|
-
* overwrite the WorkflowContext.addStep method to always raise
|
|
2927
|
+
* overwrite the WorkflowContext.addStep method to always raise WorkflowAuthError
|
|
3286
2928
|
* error in order to stop the execution whenever we encounter a step.
|
|
3287
2929
|
*
|
|
3288
2930
|
* @param _step
|
|
3289
2931
|
*/
|
|
3290
2932
|
async addStep(_step) {
|
|
3291
|
-
throw new
|
|
2933
|
+
throw new WorkflowAuthError(_DisabledWorkflowContext.disabledMessage);
|
|
3292
2934
|
}
|
|
3293
2935
|
/**
|
|
3294
|
-
* overwrite cancel method to throw
|
|
2936
|
+
* overwrite cancel method to throw WorkflowAuthError with the disabledMessage
|
|
3295
2937
|
*/
|
|
3296
2938
|
async cancel() {
|
|
3297
|
-
throw new
|
|
2939
|
+
throw new WorkflowAuthError(_DisabledWorkflowContext.disabledMessage);
|
|
3298
2940
|
}
|
|
3299
2941
|
/**
|
|
3300
2942
|
* copies the passed context to create a DisabledWorkflowContext. Then, runs the
|
|
@@ -3317,18 +2959,14 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
|
|
|
3317
2959
|
headers: context.headers,
|
|
3318
2960
|
steps: [],
|
|
3319
2961
|
url: context.url,
|
|
3320
|
-
failureUrl: context.failureUrl,
|
|
3321
2962
|
initialPayload: context.requestPayload,
|
|
3322
2963
|
env: context.env,
|
|
3323
|
-
retries: context.retries,
|
|
3324
|
-
retryDelay: context.retryDelay,
|
|
3325
|
-
flowControl: context.flowControl,
|
|
3326
2964
|
label: context.label
|
|
3327
2965
|
});
|
|
3328
2966
|
try {
|
|
3329
2967
|
await routeFunction(disabledContext);
|
|
3330
2968
|
} catch (error) {
|
|
3331
|
-
if (isInstanceOf(error,
|
|
2969
|
+
if (isInstanceOf(error, WorkflowAuthError) && error.stepName === this.disabledMessage || isInstanceOf(error, WorkflowNonRetryableError) || isInstanceOf(error, WorkflowRetryAfterError)) {
|
|
3332
2970
|
return ok("step-found");
|
|
3333
2971
|
}
|
|
3334
2972
|
console.warn(
|
|
@@ -3388,7 +3026,7 @@ var deduplicateSteps = (steps) => {
|
|
|
3388
3026
|
}
|
|
3389
3027
|
return deduplicatedSteps;
|
|
3390
3028
|
};
|
|
3391
|
-
var checkIfLastOneIsDuplicate = async (steps,
|
|
3029
|
+
var checkIfLastOneIsDuplicate = async (steps, dispatchDebug) => {
|
|
3392
3030
|
if (steps.length < 2) {
|
|
3393
3031
|
return false;
|
|
3394
3032
|
}
|
|
@@ -3399,14 +3037,41 @@ var checkIfLastOneIsDuplicate = async (steps, debug) => {
|
|
|
3399
3037
|
const step = steps[index];
|
|
3400
3038
|
if (step.stepId === lastStepId && step.targetStep === lastTargetStepId) {
|
|
3401
3039
|
const message = `Upstash Workflow: The step '${step.stepName}' with id '${step.stepId}' has run twice during workflow execution. Rest of the workflow will continue running as usual.`;
|
|
3402
|
-
await
|
|
3403
|
-
|
|
3040
|
+
await dispatchDebug?.("onWarning", {
|
|
3041
|
+
warning: message
|
|
3042
|
+
});
|
|
3404
3043
|
return true;
|
|
3405
3044
|
}
|
|
3406
3045
|
}
|
|
3407
3046
|
return false;
|
|
3408
3047
|
};
|
|
3409
3048
|
var validateRequest = (request) => {
|
|
3049
|
+
if (request.headers.get(WORKFLOW_UNKOWN_SDK_VERSION_HEADER)) {
|
|
3050
|
+
const workflowRunId2 = request.headers.get(WORKFLOW_ID_HEADER);
|
|
3051
|
+
if (!workflowRunId2) {
|
|
3052
|
+
throw new WorkflowError(
|
|
3053
|
+
"Couldn't get workflow id from header when handling unknown sdk request"
|
|
3054
|
+
);
|
|
3055
|
+
}
|
|
3056
|
+
return {
|
|
3057
|
+
unknownSdk: true,
|
|
3058
|
+
isFirstInvocation: true,
|
|
3059
|
+
workflowRunId: workflowRunId2
|
|
3060
|
+
};
|
|
3061
|
+
}
|
|
3062
|
+
if (request.headers.get(WORKFLOW_FAILURE_CALLBACK_HEADER)) {
|
|
3063
|
+
const workflowRunId2 = request.headers.get(WORKFLOW_ID_HEADER);
|
|
3064
|
+
if (!workflowRunId2) {
|
|
3065
|
+
throw new WorkflowError(
|
|
3066
|
+
"Couldn't get workflow id from header when handling failure callback request"
|
|
3067
|
+
);
|
|
3068
|
+
}
|
|
3069
|
+
return {
|
|
3070
|
+
unknownSdk: false,
|
|
3071
|
+
isFirstInvocation: true,
|
|
3072
|
+
workflowRunId: workflowRunId2
|
|
3073
|
+
};
|
|
3074
|
+
}
|
|
3410
3075
|
const versionHeader = request.headers.get(WORKFLOW_PROTOCOL_VERSION_HEADER);
|
|
3411
3076
|
const isFirstInvocation = !versionHeader;
|
|
3412
3077
|
if (!isFirstInvocation && versionHeader !== WORKFLOW_PROTOCOL_VERSION) {
|
|
@@ -3420,11 +3085,20 @@ var validateRequest = (request) => {
|
|
|
3420
3085
|
}
|
|
3421
3086
|
return {
|
|
3422
3087
|
isFirstInvocation,
|
|
3423
|
-
workflowRunId
|
|
3088
|
+
workflowRunId,
|
|
3089
|
+
unknownSdk: false
|
|
3424
3090
|
};
|
|
3425
3091
|
};
|
|
3426
|
-
var parseRequest = async (
|
|
3427
|
-
|
|
3092
|
+
var parseRequest = async ({
|
|
3093
|
+
requestPayload,
|
|
3094
|
+
isFirstInvocation,
|
|
3095
|
+
unknownSdk,
|
|
3096
|
+
workflowRunId,
|
|
3097
|
+
requester,
|
|
3098
|
+
messageId,
|
|
3099
|
+
dispatchDebug
|
|
3100
|
+
}) => {
|
|
3101
|
+
if (isFirstInvocation && !unknownSdk) {
|
|
3428
3102
|
return {
|
|
3429
3103
|
rawInitialPayload: requestPayload ?? "",
|
|
3430
3104
|
steps: [],
|
|
@@ -3434,16 +3108,14 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
|
|
|
3434
3108
|
} else {
|
|
3435
3109
|
let rawSteps;
|
|
3436
3110
|
if (!requestPayload) {
|
|
3437
|
-
await
|
|
3438
|
-
"
|
|
3439
|
-
|
|
3440
|
-
"request payload is empty, steps will be fetched from QStash."
|
|
3441
|
-
);
|
|
3111
|
+
await dispatchDebug?.("onInfo", {
|
|
3112
|
+
info: "request payload is empty, steps will be fetched from QStash."
|
|
3113
|
+
});
|
|
3442
3114
|
const { steps: fetchedSteps, workflowRunEnded } = await getSteps(
|
|
3443
3115
|
requester,
|
|
3444
3116
|
workflowRunId,
|
|
3445
3117
|
messageId,
|
|
3446
|
-
|
|
3118
|
+
dispatchDebug
|
|
3447
3119
|
);
|
|
3448
3120
|
if (workflowRunEnded) {
|
|
3449
3121
|
return {
|
|
@@ -3458,7 +3130,7 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
|
|
|
3458
3130
|
rawSteps = JSON.parse(requestPayload);
|
|
3459
3131
|
}
|
|
3460
3132
|
const { rawInitialPayload, steps } = processRawSteps(rawSteps);
|
|
3461
|
-
const isLastDuplicate = await checkIfLastOneIsDuplicate(steps,
|
|
3133
|
+
const isLastDuplicate = await checkIfLastOneIsDuplicate(steps, dispatchDebug);
|
|
3462
3134
|
const deduplicatedSteps = deduplicateSteps(steps);
|
|
3463
3135
|
return {
|
|
3464
3136
|
rawInitialPayload,
|
|
@@ -3468,16 +3140,21 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
|
|
|
3468
3140
|
};
|
|
3469
3141
|
}
|
|
3470
3142
|
};
|
|
3471
|
-
var handleFailure = async (
|
|
3472
|
-
|
|
3143
|
+
var handleFailure = async ({
|
|
3144
|
+
request,
|
|
3145
|
+
requestPayload,
|
|
3146
|
+
qstashClient,
|
|
3147
|
+
initialPayloadParser,
|
|
3148
|
+
routeFunction,
|
|
3149
|
+
failureFunction,
|
|
3150
|
+
env,
|
|
3151
|
+
dispatchDebug
|
|
3152
|
+
}) => {
|
|
3153
|
+
if (request.headers.get(WORKFLOW_FAILURE_HEADER) !== "true" && !request.headers.get(WORKFLOW_FAILURE_CALLBACK_HEADER)) {
|
|
3473
3154
|
return ok({ result: "not-failure-callback" });
|
|
3474
3155
|
}
|
|
3475
3156
|
if (!failureFunction) {
|
|
3476
|
-
return
|
|
3477
|
-
new WorkflowError(
|
|
3478
|
-
"Workflow endpoint is called to handle a failure, but a failureFunction is not provided in serve options. Either provide a failureUrl or a failureFunction."
|
|
3479
|
-
)
|
|
3480
|
-
);
|
|
3157
|
+
return ok({ result: "failure-function-undefined" });
|
|
3481
3158
|
}
|
|
3482
3159
|
try {
|
|
3483
3160
|
const { status, header, body, url, sourceBody, workflowRunId } = JSON.parse(requestPayload);
|
|
@@ -3505,23 +3182,21 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
|
|
|
3505
3182
|
headers: userHeaders,
|
|
3506
3183
|
steps: [],
|
|
3507
3184
|
url,
|
|
3508
|
-
failureUrl: url,
|
|
3509
|
-
debug,
|
|
3510
3185
|
env,
|
|
3511
|
-
retries,
|
|
3512
|
-
retryDelay,
|
|
3513
|
-
flowControl,
|
|
3514
3186
|
telemetry: void 0,
|
|
3515
3187
|
// not going to make requests in authentication check
|
|
3516
|
-
label: userHeaders.get(WORKFLOW_LABEL_HEADER) ?? void 0
|
|
3188
|
+
label: userHeaders.get(WORKFLOW_LABEL_HEADER) ?? void 0,
|
|
3189
|
+
middlewareManager: void 0
|
|
3517
3190
|
});
|
|
3518
3191
|
const authCheck = await DisabledWorkflowContext.tryAuthentication(
|
|
3519
3192
|
routeFunction,
|
|
3520
3193
|
workflowContext
|
|
3521
3194
|
);
|
|
3522
3195
|
if (authCheck.isErr()) {
|
|
3523
|
-
await
|
|
3524
|
-
|
|
3196
|
+
await dispatchDebug?.("onError", {
|
|
3197
|
+
error: authCheck.error
|
|
3198
|
+
});
|
|
3199
|
+
return err(authCheck.error);
|
|
3525
3200
|
} else if (authCheck.value === "run-ended") {
|
|
3526
3201
|
return err(new WorkflowError("Not authorized to run the failure function."));
|
|
3527
3202
|
}
|
|
@@ -3532,74 +3207,309 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
|
|
|
3532
3207
|
failHeaders: header,
|
|
3533
3208
|
failStack
|
|
3534
3209
|
});
|
|
3535
|
-
return ok({ result: "
|
|
3210
|
+
return ok({ result: "failure-function-executed", response: failureResponse });
|
|
3536
3211
|
} catch (error) {
|
|
3537
3212
|
return err(error);
|
|
3538
3213
|
}
|
|
3539
3214
|
};
|
|
3540
3215
|
|
|
3541
|
-
// src/serve/
|
|
3216
|
+
// src/serve/multi-region/handlers.ts
|
|
3542
3217
|
var import_qstash10 = require("@upstash/qstash");
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3218
|
+
|
|
3219
|
+
// src/serve/multi-region/utils.ts
|
|
3220
|
+
var VALID_REGIONS = ["EU_CENTRAL_1", "US_EAST_1"];
|
|
3221
|
+
var getRegionFromEnvironment = (environment) => {
|
|
3222
|
+
const region = environment.QSTASH_REGION;
|
|
3223
|
+
return normalizeRegionHeader(region);
|
|
3224
|
+
};
|
|
3225
|
+
function readEnvironmentVariables(environmentVariables, environment, region) {
|
|
3226
|
+
const result = {};
|
|
3227
|
+
for (const variable of environmentVariables) {
|
|
3228
|
+
const key = region ? `${region}_${variable}` : variable;
|
|
3229
|
+
result[variable] = environment[key];
|
|
3230
|
+
}
|
|
3231
|
+
return result;
|
|
3232
|
+
}
|
|
3233
|
+
function readClientEnvironmentVariables(environment, region) {
|
|
3234
|
+
return readEnvironmentVariables(["QSTASH_URL", "QSTASH_TOKEN"], environment, region);
|
|
3235
|
+
}
|
|
3236
|
+
function readReceiverEnvironmentVariables(environment, region) {
|
|
3237
|
+
return readEnvironmentVariables(
|
|
3238
|
+
["QSTASH_CURRENT_SIGNING_KEY", "QSTASH_NEXT_SIGNING_KEY"],
|
|
3239
|
+
environment,
|
|
3240
|
+
region
|
|
3548
3241
|
);
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3242
|
+
}
|
|
3243
|
+
function normalizeRegionHeader(region) {
|
|
3244
|
+
if (!region) {
|
|
3245
|
+
return void 0;
|
|
3246
|
+
}
|
|
3247
|
+
region = region.replaceAll("-", "_").toUpperCase();
|
|
3248
|
+
if (VALID_REGIONS.includes(region)) {
|
|
3249
|
+
return region;
|
|
3250
|
+
}
|
|
3251
|
+
console.warn(
|
|
3252
|
+
`[Upstash Workflow] Invalid UPSTASH-REGION header value: "${region}". Expected one of: ${VALID_REGIONS.join(
|
|
3253
|
+
", "
|
|
3254
|
+
)}.`
|
|
3255
|
+
);
|
|
3256
|
+
return void 0;
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
// src/serve/multi-region/handlers.ts
|
|
3260
|
+
var getHandlersForRequest = (qstashHandlers, regionHeader, isFirstInvocation) => {
|
|
3261
|
+
if (qstashHandlers.mode === "single-region") {
|
|
3262
|
+
return qstashHandlers.handlers;
|
|
3263
|
+
}
|
|
3264
|
+
let targetRegion;
|
|
3265
|
+
if (isFirstInvocation) {
|
|
3266
|
+
targetRegion = qstashHandlers.defaultRegion;
|
|
3267
|
+
} else {
|
|
3268
|
+
const normalizedRegion = regionHeader ? normalizeRegionHeader(regionHeader) : void 0;
|
|
3269
|
+
targetRegion = normalizedRegion ?? qstashHandlers.defaultRegion;
|
|
3270
|
+
}
|
|
3271
|
+
const handler = qstashHandlers.handlers[targetRegion];
|
|
3272
|
+
if (!handler) {
|
|
3273
|
+
console.warn(
|
|
3274
|
+
`[Upstash Workflow] No handler found for region "${targetRegion}". Falling back to default region.`
|
|
3275
|
+
);
|
|
3276
|
+
return qstashHandlers.handlers[qstashHandlers.defaultRegion];
|
|
3277
|
+
}
|
|
3278
|
+
return handler;
|
|
3279
|
+
};
|
|
3280
|
+
var createRegionalHandler = (environment, receiverConfig, region, clientOptions) => {
|
|
3281
|
+
const clientEnv = readClientEnvironmentVariables(environment, region);
|
|
3282
|
+
const client = new import_qstash10.Client({
|
|
3283
|
+
...clientOptions,
|
|
3284
|
+
baseUrl: clientEnv.QSTASH_URL,
|
|
3285
|
+
token: clientEnv.QSTASH_TOKEN
|
|
3286
|
+
});
|
|
3287
|
+
const receiver = getReceiver(environment, receiverConfig, region);
|
|
3288
|
+
return { client, receiver };
|
|
3289
|
+
};
|
|
3290
|
+
var shouldUseMultiRegionMode = (environment, qstashClientOption) => {
|
|
3291
|
+
const hasRegionEnv = Boolean(getRegionFromEnvironment(environment));
|
|
3292
|
+
if (hasRegionEnv && (!qstashClientOption || !("http" in qstashClientOption))) {
|
|
3293
|
+
return {
|
|
3294
|
+
isMultiRegion: true,
|
|
3295
|
+
defaultRegion: getRegionFromEnvironment(environment),
|
|
3296
|
+
clientOptions: qstashClientOption
|
|
3297
|
+
};
|
|
3298
|
+
} else {
|
|
3299
|
+
return { isMultiRegion: false };
|
|
3300
|
+
}
|
|
3301
|
+
};
|
|
3302
|
+
var getQStashHandlers = ({
|
|
3303
|
+
environment,
|
|
3304
|
+
qstashClientOption,
|
|
3305
|
+
receiverConfig
|
|
3306
|
+
}) => {
|
|
3307
|
+
const multiRegion = shouldUseMultiRegionMode(environment, qstashClientOption);
|
|
3308
|
+
if (multiRegion.isMultiRegion) {
|
|
3309
|
+
const regions = ["US_EAST_1", "EU_CENTRAL_1"];
|
|
3310
|
+
const handlers = {};
|
|
3311
|
+
for (const region of regions) {
|
|
3312
|
+
try {
|
|
3313
|
+
handlers[region] = createRegionalHandler(
|
|
3314
|
+
environment,
|
|
3315
|
+
receiverConfig,
|
|
3316
|
+
region,
|
|
3317
|
+
multiRegion.clientOptions
|
|
3594
3318
|
);
|
|
3319
|
+
} catch (error) {
|
|
3320
|
+
console.warn(`[Upstash Workflow] Failed to create handler for region ${region}:`, error);
|
|
3595
3321
|
}
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3322
|
+
}
|
|
3323
|
+
return {
|
|
3324
|
+
mode: "multi-region",
|
|
3325
|
+
handlers,
|
|
3326
|
+
defaultRegion: multiRegion.defaultRegion
|
|
3327
|
+
};
|
|
3328
|
+
} else {
|
|
3329
|
+
return {
|
|
3330
|
+
mode: "single-region",
|
|
3331
|
+
handlers: {
|
|
3332
|
+
client: qstashClientOption && "http" in qstashClientOption ? qstashClientOption : new import_qstash10.Client({
|
|
3333
|
+
...qstashClientOption,
|
|
3334
|
+
baseUrl: environment.QSTASH_URL,
|
|
3335
|
+
token: environment.QSTASH_TOKEN
|
|
3336
|
+
}),
|
|
3337
|
+
receiver: getReceiver(environment, receiverConfig)
|
|
3338
|
+
}
|
|
3339
|
+
};
|
|
3340
|
+
}
|
|
3341
|
+
};
|
|
3342
|
+
var getReceiver = (environment, receiverConfig, region) => {
|
|
3343
|
+
if (typeof receiverConfig === "string") {
|
|
3344
|
+
if (receiverConfig === "set-to-undefined") {
|
|
3345
|
+
return void 0;
|
|
3346
|
+
}
|
|
3347
|
+
const receiverEnv = readReceiverEnvironmentVariables(environment, region);
|
|
3348
|
+
return receiverEnv.QSTASH_CURRENT_SIGNING_KEY && receiverEnv.QSTASH_NEXT_SIGNING_KEY ? new import_qstash10.Receiver({
|
|
3349
|
+
currentSigningKey: receiverEnv.QSTASH_CURRENT_SIGNING_KEY,
|
|
3350
|
+
nextSigningKey: receiverEnv.QSTASH_NEXT_SIGNING_KEY
|
|
3351
|
+
}) : void 0;
|
|
3352
|
+
} else {
|
|
3353
|
+
return receiverConfig;
|
|
3354
|
+
}
|
|
3355
|
+
};
|
|
3356
|
+
var getQStashHandlerOptions = (...params) => {
|
|
3357
|
+
const handlers = getQStashHandlers(...params);
|
|
3358
|
+
return {
|
|
3359
|
+
qstashHandlers: handlers,
|
|
3360
|
+
defaultReceiver: handlers.mode === "single-region" ? handlers.handlers.receiver : handlers.handlers[handlers.defaultRegion].receiver,
|
|
3361
|
+
defaultClient: handlers.mode === "single-region" ? handlers.handlers.client : handlers.handlers[handlers.defaultRegion].client
|
|
3362
|
+
};
|
|
3363
|
+
};
|
|
3364
|
+
|
|
3365
|
+
// src/middleware/middleware.ts
|
|
3366
|
+
var WorkflowMiddleware = class {
|
|
3367
|
+
name;
|
|
3368
|
+
initCallbacks;
|
|
3369
|
+
/**
|
|
3370
|
+
* Callback functions
|
|
3371
|
+
*
|
|
3372
|
+
* Initially set to undefined, will be populated after init is called
|
|
3373
|
+
*/
|
|
3374
|
+
middlewareCallbacks = void 0;
|
|
3375
|
+
constructor(parameters) {
|
|
3376
|
+
this.name = parameters.name;
|
|
3377
|
+
if ("init" in parameters) {
|
|
3378
|
+
this.initCallbacks = parameters.init;
|
|
3379
|
+
} else {
|
|
3380
|
+
this.middlewareCallbacks = parameters.callbacks;
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
async ensureInit() {
|
|
3384
|
+
if (!this.middlewareCallbacks) {
|
|
3385
|
+
if (!this.initCallbacks) {
|
|
3386
|
+
throw new WorkflowError(`Middleware "${this.name}" has no callbacks or init defined.`);
|
|
3387
|
+
}
|
|
3388
|
+
this.middlewareCallbacks = await this.initCallbacks();
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
/**
|
|
3392
|
+
* Gets a callback function by name.
|
|
3393
|
+
*
|
|
3394
|
+
* @param callback name of the callback to retrieve
|
|
3395
|
+
*/
|
|
3396
|
+
getCallback(callback) {
|
|
3397
|
+
return this.middlewareCallbacks?.[callback];
|
|
3398
|
+
}
|
|
3399
|
+
};
|
|
3400
|
+
|
|
3401
|
+
// src/middleware/logging.ts
|
|
3402
|
+
var loggingMiddleware = new WorkflowMiddleware({
|
|
3403
|
+
name: "logging",
|
|
3404
|
+
callbacks: {
|
|
3405
|
+
afterExecution(params) {
|
|
3406
|
+
const { context, ...rest } = params;
|
|
3407
|
+
console.log(" [Upstash Workflow]: Step executed:", {
|
|
3408
|
+
workflowRunId: context.workflowRunId,
|
|
3409
|
+
...rest
|
|
3410
|
+
});
|
|
3411
|
+
},
|
|
3412
|
+
beforeExecution(params) {
|
|
3413
|
+
const { context, ...rest } = params;
|
|
3414
|
+
console.log(" [Upstash Workflow]: Step execution started:", {
|
|
3415
|
+
workflowRunId: context.workflowRunId,
|
|
3416
|
+
...rest
|
|
3601
3417
|
});
|
|
3602
3418
|
},
|
|
3419
|
+
runStarted(params) {
|
|
3420
|
+
const { context, ...rest } = params;
|
|
3421
|
+
console.log(" [Upstash Workflow]: Workflow run started:", {
|
|
3422
|
+
workflowRunId: context.workflowRunId,
|
|
3423
|
+
...rest
|
|
3424
|
+
});
|
|
3425
|
+
},
|
|
3426
|
+
runCompleted(params) {
|
|
3427
|
+
const { context, ...rest } = params;
|
|
3428
|
+
console.log(" [Upstash Workflow]: Workflow run completed:", {
|
|
3429
|
+
workflowRunId: context.workflowRunId,
|
|
3430
|
+
...rest
|
|
3431
|
+
});
|
|
3432
|
+
},
|
|
3433
|
+
onError: onErrorWithConsole,
|
|
3434
|
+
onWarning: onWarningWithConsole,
|
|
3435
|
+
onInfo: onInfoWithConsole
|
|
3436
|
+
}
|
|
3437
|
+
});
|
|
3438
|
+
|
|
3439
|
+
// src/serve/options.ts
|
|
3440
|
+
var createResponseData = (workflowRunId, detailedFinishCondition) => {
|
|
3441
|
+
const baseHeaders = {
|
|
3442
|
+
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
|
|
3443
|
+
"Upstash-workflow-sdk": VERSION
|
|
3444
|
+
};
|
|
3445
|
+
if (detailedFinishCondition?.condition === "auth-fail") {
|
|
3446
|
+
return {
|
|
3447
|
+
text: JSON.stringify({
|
|
3448
|
+
message: AUTH_FAIL_MESSAGE,
|
|
3449
|
+
workflowRunId
|
|
3450
|
+
}),
|
|
3451
|
+
status: 400,
|
|
3452
|
+
headers: baseHeaders
|
|
3453
|
+
};
|
|
3454
|
+
} else if (detailedFinishCondition?.condition === "non-retryable-error") {
|
|
3455
|
+
return {
|
|
3456
|
+
text: JSON.stringify(formatWorkflowError(detailedFinishCondition.result)),
|
|
3457
|
+
status: 489,
|
|
3458
|
+
headers: {
|
|
3459
|
+
...baseHeaders,
|
|
3460
|
+
"Upstash-NonRetryable-Error": "true"
|
|
3461
|
+
}
|
|
3462
|
+
};
|
|
3463
|
+
} else if (detailedFinishCondition?.condition === "retry-after-error") {
|
|
3464
|
+
return {
|
|
3465
|
+
text: JSON.stringify(formatWorkflowError(detailedFinishCondition.result)),
|
|
3466
|
+
status: 429,
|
|
3467
|
+
headers: {
|
|
3468
|
+
...baseHeaders,
|
|
3469
|
+
"Retry-After": detailedFinishCondition.result.retryAfter.toString()
|
|
3470
|
+
}
|
|
3471
|
+
};
|
|
3472
|
+
} else if (detailedFinishCondition?.condition === "failure-callback-executed") {
|
|
3473
|
+
return {
|
|
3474
|
+
text: JSON.stringify({ result: detailedFinishCondition.result ?? void 0 }),
|
|
3475
|
+
status: 200,
|
|
3476
|
+
headers: baseHeaders
|
|
3477
|
+
};
|
|
3478
|
+
} else if (detailedFinishCondition?.condition === "failure-callback-undefined") {
|
|
3479
|
+
return {
|
|
3480
|
+
text: JSON.stringify({
|
|
3481
|
+
workflowRunId,
|
|
3482
|
+
finishCondition: detailedFinishCondition.condition
|
|
3483
|
+
}),
|
|
3484
|
+
status: 200,
|
|
3485
|
+
headers: {
|
|
3486
|
+
...baseHeaders,
|
|
3487
|
+
"Upstash-Workflow-Failure-Callback-Notfound": "true"
|
|
3488
|
+
}
|
|
3489
|
+
};
|
|
3490
|
+
}
|
|
3491
|
+
return {
|
|
3492
|
+
text: JSON.stringify({
|
|
3493
|
+
workflowRunId,
|
|
3494
|
+
finishCondition: detailedFinishCondition.condition
|
|
3495
|
+
}),
|
|
3496
|
+
status: 200,
|
|
3497
|
+
headers: baseHeaders
|
|
3498
|
+
};
|
|
3499
|
+
};
|
|
3500
|
+
var processOptions = (options, internalOptions) => {
|
|
3501
|
+
const environment = options?.env ?? (typeof process === "undefined" ? {} : process.env);
|
|
3502
|
+
const {
|
|
3503
|
+
qstashHandlers,
|
|
3504
|
+
defaultClient: qstashClient,
|
|
3505
|
+
defaultReceiver: receiver
|
|
3506
|
+
} = getQStashHandlerOptions({
|
|
3507
|
+
environment,
|
|
3508
|
+
qstashClientOption: options?.qstashClient,
|
|
3509
|
+
receiverConfig: options && "receiver" in options ? options.receiver ? options.receiver : "set-to-undefined" : "not-set"
|
|
3510
|
+
});
|
|
3511
|
+
return {
|
|
3512
|
+
qstashClient,
|
|
3603
3513
|
initialPayloadParser: (initialRequest) => {
|
|
3604
3514
|
if (!initialRequest) {
|
|
3605
3515
|
return void 0;
|
|
@@ -3614,35 +3524,38 @@ var processOptions = (options) => {
|
|
|
3614
3524
|
throw error;
|
|
3615
3525
|
}
|
|
3616
3526
|
},
|
|
3617
|
-
receiver
|
|
3618
|
-
currentSigningKey: environment.QSTASH_CURRENT_SIGNING_KEY,
|
|
3619
|
-
nextSigningKey: environment.QSTASH_NEXT_SIGNING_KEY
|
|
3620
|
-
}) : void 0,
|
|
3527
|
+
receiver,
|
|
3621
3528
|
baseUrl: environment.UPSTASH_WORKFLOW_URL,
|
|
3622
3529
|
env: environment,
|
|
3623
|
-
retries: DEFAULT_RETRIES,
|
|
3624
|
-
useJSONContent: false,
|
|
3625
3530
|
disableTelemetry: false,
|
|
3626
|
-
|
|
3627
|
-
|
|
3531
|
+
...options,
|
|
3532
|
+
// merge middlewares
|
|
3533
|
+
middlewares: [options?.middlewares ?? [], options?.verbose ? [loggingMiddleware] : []].flat(),
|
|
3534
|
+
internal: {
|
|
3535
|
+
generateResponse: internalOptions?.generateResponse ?? ((responseData) => {
|
|
3536
|
+
return new Response(responseData.text, {
|
|
3537
|
+
status: responseData.status,
|
|
3538
|
+
headers: responseData.headers
|
|
3539
|
+
});
|
|
3540
|
+
}),
|
|
3541
|
+
useJSONContent: internalOptions?.useJSONContent ?? false,
|
|
3542
|
+
qstashHandlers
|
|
3543
|
+
}
|
|
3628
3544
|
};
|
|
3629
3545
|
};
|
|
3630
|
-
var determineUrls = async (request, url, baseUrl,
|
|
3546
|
+
var determineUrls = async (request, url, baseUrl, dispatchDebug) => {
|
|
3631
3547
|
const initialWorkflowUrl = url ?? request.url;
|
|
3632
3548
|
const workflowUrl = baseUrl ? initialWorkflowUrl.replace(/^(https?:\/\/[^/]+)(\/.*)?$/, (_, matchedBaseUrl, path) => {
|
|
3633
3549
|
return baseUrl + (path || "");
|
|
3634
3550
|
}) : initialWorkflowUrl;
|
|
3635
3551
|
if (workflowUrl !== initialWorkflowUrl) {
|
|
3636
|
-
await
|
|
3637
|
-
|
|
3638
|
-
originalURL: initialWorkflowUrl,
|
|
3639
|
-
updatedURL: workflowUrl
|
|
3552
|
+
await dispatchDebug("onInfo", {
|
|
3553
|
+
info: `The workflow URL's base URL has been replaced with the provided baseUrl. Original URL: ${initialWorkflowUrl}, New URL: ${workflowUrl}`
|
|
3640
3554
|
});
|
|
3641
3555
|
}
|
|
3642
|
-
const workflowFailureUrl = failureFunction ? workflowUrl : failureUrl;
|
|
3643
3556
|
if (workflowUrl.includes("localhost")) {
|
|
3644
|
-
await
|
|
3645
|
-
|
|
3557
|
+
await dispatchDebug("onInfo", {
|
|
3558
|
+
info: `Workflow URL contains localhost. This can happen in local development, but shouldn't happen in production unless you have a route which contains localhost. Received: ${workflowUrl}`
|
|
3646
3559
|
});
|
|
3647
3560
|
}
|
|
3648
3561
|
if (!(workflowUrl.startsWith("http://") || workflowUrl.startsWith("https://"))) {
|
|
@@ -3651,205 +3564,224 @@ var determineUrls = async (request, url, baseUrl, failureFunction, failureUrl, d
|
|
|
3651
3564
|
);
|
|
3652
3565
|
}
|
|
3653
3566
|
return {
|
|
3654
|
-
workflowUrl
|
|
3655
|
-
workflowFailureUrl
|
|
3567
|
+
workflowUrl
|
|
3656
3568
|
};
|
|
3657
3569
|
};
|
|
3658
3570
|
var AUTH_FAIL_MESSAGE = `Failed to authenticate Workflow request. If this is unexpected, see the caveat https://upstash.com/docs/workflow/basics/caveats#avoid-non-deterministic-code-outside-context-run`;
|
|
3659
3571
|
|
|
3660
3572
|
// src/serve/index.ts
|
|
3661
|
-
var serveBase = (routeFunction, telemetry2, options) => {
|
|
3573
|
+
var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
3662
3574
|
const {
|
|
3663
|
-
qstashClient,
|
|
3664
|
-
onStepFinish,
|
|
3665
3575
|
initialPayloadParser,
|
|
3666
3576
|
url,
|
|
3667
|
-
verbose,
|
|
3668
|
-
receiver,
|
|
3669
|
-
failureUrl,
|
|
3670
3577
|
failureFunction,
|
|
3671
3578
|
baseUrl,
|
|
3672
3579
|
env,
|
|
3673
|
-
retries,
|
|
3674
|
-
retryDelay,
|
|
3675
|
-
useJSONContent,
|
|
3676
3580
|
disableTelemetry,
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
} = processOptions(options);
|
|
3581
|
+
middlewares,
|
|
3582
|
+
internal
|
|
3583
|
+
} = processOptions(options, internalOptions);
|
|
3680
3584
|
telemetry2 = disableTelemetry ? void 0 : telemetry2;
|
|
3681
|
-
const
|
|
3682
|
-
const handler = async (request) => {
|
|
3683
|
-
await
|
|
3684
|
-
|
|
3585
|
+
const { generateResponse: responseGenerator, useJSONContent } = internal;
|
|
3586
|
+
const handler = async (request, middlewareManager) => {
|
|
3587
|
+
await middlewareManager.dispatchDebug("onInfo", {
|
|
3588
|
+
info: `Received request for workflow execution.`
|
|
3589
|
+
});
|
|
3590
|
+
const { workflowUrl } = await determineUrls(
|
|
3685
3591
|
request,
|
|
3686
3592
|
url,
|
|
3687
3593
|
baseUrl,
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3594
|
+
middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3595
|
+
);
|
|
3596
|
+
const { isFirstInvocation, workflowRunId, unknownSdk } = validateRequest(request);
|
|
3597
|
+
const regionHeader = request.headers.get("upstash-region");
|
|
3598
|
+
const { client: regionalClient, receiver: regionalReceiver } = getHandlersForRequest(
|
|
3599
|
+
internal.qstashHandlers,
|
|
3600
|
+
regionHeader,
|
|
3601
|
+
isFirstInvocation
|
|
3691
3602
|
);
|
|
3692
3603
|
const requestPayload = await getPayload(request) ?? "";
|
|
3693
|
-
await verifyRequest(requestPayload, request.headers.get("upstash-signature"),
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3604
|
+
await verifyRequest(requestPayload, request.headers.get("upstash-signature"), regionalReceiver);
|
|
3605
|
+
middlewareManager.assignWorkflowRunId(workflowRunId);
|
|
3606
|
+
await middlewareManager.dispatchDebug("onInfo", {
|
|
3607
|
+
info: `Run id identified. isFirstInvocation: ${isFirstInvocation}, unknownSdk: ${unknownSdk}`
|
|
3608
|
+
});
|
|
3609
|
+
const { rawInitialPayload, steps, isLastDuplicate, workflowRunEnded } = await parseRequest({
|
|
3697
3610
|
requestPayload,
|
|
3698
3611
|
isFirstInvocation,
|
|
3612
|
+
unknownSdk,
|
|
3699
3613
|
workflowRunId,
|
|
3700
|
-
|
|
3701
|
-
request.headers.get("upstash-message-id"),
|
|
3702
|
-
|
|
3703
|
-
);
|
|
3614
|
+
requester: regionalClient.http,
|
|
3615
|
+
messageId: request.headers.get("upstash-message-id"),
|
|
3616
|
+
dispatchDebug: middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3617
|
+
});
|
|
3704
3618
|
if (workflowRunEnded) {
|
|
3705
|
-
return
|
|
3706
|
-
|
|
3707
|
-
|
|
3619
|
+
return responseGenerator(
|
|
3620
|
+
createResponseData(workflowRunId, {
|
|
3621
|
+
condition: "workflow-already-ended"
|
|
3622
|
+
})
|
|
3623
|
+
);
|
|
3708
3624
|
}
|
|
3709
3625
|
if (isLastDuplicate) {
|
|
3710
|
-
return
|
|
3711
|
-
|
|
3712
|
-
|
|
3626
|
+
return responseGenerator(
|
|
3627
|
+
createResponseData(workflowRunId, {
|
|
3628
|
+
condition: "duplicate-step"
|
|
3629
|
+
})
|
|
3630
|
+
);
|
|
3713
3631
|
}
|
|
3714
|
-
const failureCheck = await handleFailure(
|
|
3632
|
+
const failureCheck = await handleFailure({
|
|
3715
3633
|
request,
|
|
3716
3634
|
requestPayload,
|
|
3717
|
-
qstashClient,
|
|
3635
|
+
qstashClient: regionalClient,
|
|
3718
3636
|
initialPayloadParser,
|
|
3719
3637
|
routeFunction,
|
|
3720
3638
|
failureFunction,
|
|
3721
3639
|
env,
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
flowControl,
|
|
3725
|
-
debug
|
|
3726
|
-
);
|
|
3640
|
+
dispatchDebug: middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3641
|
+
});
|
|
3727
3642
|
if (failureCheck.isErr()) {
|
|
3728
3643
|
throw failureCheck.error;
|
|
3729
|
-
} else if (failureCheck.value.result === "
|
|
3730
|
-
await
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3644
|
+
} else if (failureCheck.value.result === "failure-function-executed") {
|
|
3645
|
+
await middlewareManager.dispatchDebug("onInfo", {
|
|
3646
|
+
info: `Handled failure callback.`
|
|
3647
|
+
});
|
|
3648
|
+
return responseGenerator(
|
|
3649
|
+
createResponseData(workflowRunId, {
|
|
3650
|
+
condition: "failure-callback-executed",
|
|
3651
|
+
result: failureCheck.value.response
|
|
3652
|
+
})
|
|
3653
|
+
);
|
|
3654
|
+
} else if (failureCheck.value.result === "failure-function-undefined") {
|
|
3655
|
+
await middlewareManager.dispatchDebug("onInfo", {
|
|
3656
|
+
info: `Failure callback invoked but no failure function defined.`
|
|
3734
3657
|
});
|
|
3658
|
+
return responseGenerator(
|
|
3659
|
+
createResponseData(workflowRunId, {
|
|
3660
|
+
condition: "failure-callback-undefined"
|
|
3661
|
+
})
|
|
3662
|
+
);
|
|
3735
3663
|
}
|
|
3736
3664
|
const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
|
|
3737
3665
|
const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
|
|
3738
3666
|
const workflowContext = new WorkflowContext({
|
|
3739
|
-
qstashClient,
|
|
3667
|
+
qstashClient: regionalClient,
|
|
3740
3668
|
workflowRunId,
|
|
3741
3669
|
initialPayload: initialPayloadParser(rawInitialPayload),
|
|
3742
3670
|
headers: recreateUserHeaders(request.headers),
|
|
3743
3671
|
steps,
|
|
3744
3672
|
url: workflowUrl,
|
|
3745
|
-
failureUrl: workflowFailureUrl,
|
|
3746
|
-
debug,
|
|
3747
3673
|
env,
|
|
3748
|
-
retries,
|
|
3749
|
-
retryDelay,
|
|
3750
3674
|
telemetry: telemetry2,
|
|
3751
3675
|
invokeCount,
|
|
3752
|
-
|
|
3753
|
-
|
|
3676
|
+
label,
|
|
3677
|
+
middlewareManager
|
|
3754
3678
|
});
|
|
3755
3679
|
const authCheck = await DisabledWorkflowContext.tryAuthentication(
|
|
3756
3680
|
routeFunction,
|
|
3757
3681
|
workflowContext
|
|
3758
3682
|
);
|
|
3759
3683
|
if (authCheck.isErr()) {
|
|
3760
|
-
await debug?.log("ERROR", "ERROR", { error: authCheck.error.message });
|
|
3761
3684
|
throw authCheck.error;
|
|
3762
3685
|
} else if (authCheck.value === "run-ended") {
|
|
3763
|
-
await
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3686
|
+
await middlewareManager.dispatchDebug("onError", {
|
|
3687
|
+
error: new Error(AUTH_FAIL_MESSAGE)
|
|
3688
|
+
});
|
|
3689
|
+
return responseGenerator(
|
|
3690
|
+
createResponseData(isFirstInvocation ? "no-workflow-id" : workflowContext.workflowRunId, {
|
|
3691
|
+
condition: "auth-fail"
|
|
3692
|
+
})
|
|
3768
3693
|
);
|
|
3769
3694
|
}
|
|
3770
3695
|
const callReturnCheck = await handleThirdPartyCallResult({
|
|
3771
3696
|
request,
|
|
3772
3697
|
requestPayload: rawInitialPayload,
|
|
3773
|
-
client:
|
|
3698
|
+
client: regionalClient,
|
|
3774
3699
|
workflowUrl,
|
|
3775
|
-
failureUrl: workflowFailureUrl,
|
|
3776
|
-
retries,
|
|
3777
|
-
retryDelay,
|
|
3778
|
-
flowControl,
|
|
3779
3700
|
telemetry: telemetry2,
|
|
3780
|
-
|
|
3701
|
+
middlewareManager
|
|
3781
3702
|
});
|
|
3782
3703
|
if (callReturnCheck.isErr()) {
|
|
3783
|
-
await debug?.log("ERROR", "SUBMIT_THIRD_PARTY_RESULT", {
|
|
3784
|
-
error: callReturnCheck.error.message
|
|
3785
|
-
});
|
|
3786
3704
|
throw callReturnCheck.error;
|
|
3787
3705
|
} else if (callReturnCheck.value === "continue-workflow") {
|
|
3788
3706
|
const result = isFirstInvocation ? await triggerFirstInvocation({
|
|
3789
3707
|
workflowContext,
|
|
3790
3708
|
useJSONContent,
|
|
3791
3709
|
telemetry: telemetry2,
|
|
3792
|
-
|
|
3793
|
-
|
|
3710
|
+
invokeCount,
|
|
3711
|
+
middlewareManager,
|
|
3712
|
+
unknownSdk
|
|
3794
3713
|
}) : await triggerRouteFunction({
|
|
3795
|
-
onStep: async () =>
|
|
3714
|
+
onStep: async () => {
|
|
3715
|
+
if (steps.length === 1) {
|
|
3716
|
+
await middlewareManager.dispatchLifecycle("runStarted", {});
|
|
3717
|
+
}
|
|
3718
|
+
return await routeFunction(workflowContext);
|
|
3719
|
+
},
|
|
3796
3720
|
onCleanup: async (result2) => {
|
|
3797
|
-
await
|
|
3721
|
+
await middlewareManager.dispatchLifecycle("runCompleted", {
|
|
3722
|
+
result: result2
|
|
3723
|
+
});
|
|
3724
|
+
await triggerWorkflowDelete(
|
|
3725
|
+
workflowContext,
|
|
3726
|
+
result2,
|
|
3727
|
+
false,
|
|
3728
|
+
middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3729
|
+
);
|
|
3798
3730
|
},
|
|
3799
3731
|
onCancel: async () => {
|
|
3800
3732
|
await makeCancelRequest(workflowContext.qstashClient.http, workflowRunId);
|
|
3801
3733
|
},
|
|
3802
|
-
|
|
3734
|
+
middlewareManager
|
|
3803
3735
|
});
|
|
3804
3736
|
if (result.isOk() && isInstanceOf(result.value, WorkflowNonRetryableError)) {
|
|
3805
|
-
return
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3737
|
+
return responseGenerator(
|
|
3738
|
+
createResponseData(workflowRunId, {
|
|
3739
|
+
condition: "non-retryable-error",
|
|
3740
|
+
result: result.value
|
|
3741
|
+
})
|
|
3742
|
+
);
|
|
3809
3743
|
}
|
|
3810
3744
|
if (result.isOk() && isInstanceOf(result.value, WorkflowRetryAfterError)) {
|
|
3811
|
-
return
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3745
|
+
return responseGenerator(
|
|
3746
|
+
createResponseData(workflowRunId, {
|
|
3747
|
+
condition: "retry-after-error",
|
|
3748
|
+
result: result.value
|
|
3749
|
+
})
|
|
3750
|
+
);
|
|
3815
3751
|
}
|
|
3816
3752
|
if (result.isErr()) {
|
|
3817
|
-
await debug?.log("ERROR", "ERROR", { error: result.error.message });
|
|
3818
3753
|
throw result.error;
|
|
3819
3754
|
}
|
|
3820
|
-
await
|
|
3821
|
-
|
|
3822
|
-
condition: "success"
|
|
3755
|
+
await middlewareManager.dispatchDebug("onInfo", {
|
|
3756
|
+
info: `Workflow endpoint execution completed successfully.`
|
|
3823
3757
|
});
|
|
3758
|
+
return responseGenerator(
|
|
3759
|
+
createResponseData(workflowContext.workflowRunId, {
|
|
3760
|
+
condition: "success"
|
|
3761
|
+
})
|
|
3762
|
+
);
|
|
3824
3763
|
} else if (callReturnCheck.value === "workflow-ended") {
|
|
3825
|
-
return
|
|
3826
|
-
|
|
3827
|
-
|
|
3764
|
+
return responseGenerator(
|
|
3765
|
+
createResponseData(workflowContext.workflowRunId, {
|
|
3766
|
+
condition: "workflow-already-ended"
|
|
3767
|
+
})
|
|
3768
|
+
);
|
|
3828
3769
|
}
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3770
|
+
return responseGenerator(
|
|
3771
|
+
createResponseData(workflowContext.workflowRunId, {
|
|
3772
|
+
condition: "fromCallback"
|
|
3773
|
+
})
|
|
3774
|
+
);
|
|
3833
3775
|
};
|
|
3834
3776
|
const safeHandler = async (request) => {
|
|
3777
|
+
const middlewareManager = new MiddlewareManager(middlewares);
|
|
3835
3778
|
try {
|
|
3836
|
-
return await handler(request);
|
|
3779
|
+
return await handler(request, middlewareManager);
|
|
3837
3780
|
} catch (error) {
|
|
3838
3781
|
const formattedError = formatWorkflowError(error);
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
}
|
|
3842
|
-
const formattedOnErrorError = formatWorkflowError(onErrorError);
|
|
3843
|
-
const errorMessage = `Error while running onError callback: '${formattedOnErrorError.message}'.
|
|
3844
|
-
Original error: '${formattedError.message}'`;
|
|
3845
|
-
console.error(errorMessage);
|
|
3846
|
-
return new Response(JSON.stringify({ error: errorMessage }), {
|
|
3847
|
-
status: 500,
|
|
3848
|
-
headers: {
|
|
3849
|
-
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
|
|
3850
|
-
}
|
|
3851
|
-
});
|
|
3852
|
-
}
|
|
3782
|
+
await middlewareManager.dispatchDebug("onError", {
|
|
3783
|
+
error: isInstanceOf(error, Error) ? error : new Error(formattedError.message)
|
|
3784
|
+
});
|
|
3853
3785
|
return new Response(JSON.stringify(formattedError), {
|
|
3854
3786
|
status: 500,
|
|
3855
3787
|
headers: {
|
|
@@ -3896,10 +3828,14 @@ function createExpressHandler(params) {
|
|
|
3896
3828
|
headers: new Headers(request_.headers),
|
|
3897
3829
|
body: requestBody
|
|
3898
3830
|
});
|
|
3899
|
-
const { handler: serveHandler } = serveBase(
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3831
|
+
const { handler: serveHandler } = serveBase(
|
|
3832
|
+
routeFunction,
|
|
3833
|
+
telemetry,
|
|
3834
|
+
options,
|
|
3835
|
+
{
|
|
3836
|
+
useJSONContent: true
|
|
3837
|
+
}
|
|
3838
|
+
);
|
|
3903
3839
|
const response = await serveHandler(webRequest);
|
|
3904
3840
|
for (const [key, value] of response.headers.entries()) {
|
|
3905
3841
|
res.setHeader(key, value);
|
|
@@ -3919,7 +3855,8 @@ var createWorkflow = (...params) => {
|
|
|
3919
3855
|
return {
|
|
3920
3856
|
routeFunction,
|
|
3921
3857
|
options,
|
|
3922
|
-
workflowId: void 0
|
|
3858
|
+
workflowId: void 0,
|
|
3859
|
+
useJSONContent: true
|
|
3923
3860
|
};
|
|
3924
3861
|
};
|
|
3925
3862
|
var serveMany = (workflows, options) => {
|