@flowgram.ai/runtime-js 0.2.26 → 0.2.28
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/dist/esm/index.js +418 -82
- package/dist/esm/index.js.map +1 -1
- package/dist/index.js +418 -82
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -236,13 +236,16 @@ var FlowGramNode = /* @__PURE__ */ ((FlowGramNode22) => {
|
|
|
236
236
|
FlowGramNode22["Start"] = "start";
|
|
237
237
|
FlowGramNode22["End"] = "end";
|
|
238
238
|
FlowGramNode22["LLM"] = "llm";
|
|
239
|
-
FlowGramNode22["
|
|
239
|
+
FlowGramNode22["Code"] = "code";
|
|
240
240
|
FlowGramNode22["Condition"] = "condition";
|
|
241
241
|
FlowGramNode22["Loop"] = "loop";
|
|
242
242
|
FlowGramNode22["Comment"] = "comment";
|
|
243
243
|
FlowGramNode22["Group"] = "group";
|
|
244
244
|
FlowGramNode22["BlockStart"] = "block-start";
|
|
245
245
|
FlowGramNode22["BlockEnd"] = "block-end";
|
|
246
|
+
FlowGramNode22["HTTP"] = "http";
|
|
247
|
+
FlowGramNode22["Break"] = "break";
|
|
248
|
+
FlowGramNode22["Continue"] = "continue";
|
|
246
249
|
return FlowGramNode22;
|
|
247
250
|
})(FlowGramNode || {});
|
|
248
251
|
var ConditionOperation = /* @__PURE__ */ ((ConditionOperation2) => {
|
|
@@ -262,6 +265,15 @@ var ConditionOperation = /* @__PURE__ */ ((ConditionOperation2) => {
|
|
|
262
265
|
ConditionOperation2["IS_FALSE"] = "is_false";
|
|
263
266
|
return ConditionOperation2;
|
|
264
267
|
})(ConditionOperation || {});
|
|
268
|
+
var HTTPBodyType = /* @__PURE__ */ ((HTTPBodyType2) => {
|
|
269
|
+
HTTPBodyType2["None"] = "none";
|
|
270
|
+
HTTPBodyType2["FormData"] = "form-data";
|
|
271
|
+
HTTPBodyType2["XWwwFormUrlencoded"] = "x-www-form-urlencoded";
|
|
272
|
+
HTTPBodyType2["RawText"] = "raw-text";
|
|
273
|
+
HTTPBodyType2["JSON"] = "JSON";
|
|
274
|
+
HTTPBodyType2["Binary"] = "binary";
|
|
275
|
+
return HTTPBodyType2;
|
|
276
|
+
})(HTTPBodyType || {});
|
|
265
277
|
var IEngine = Symbol.for("Engine");
|
|
266
278
|
var IExecutor = Symbol.for("Executor");
|
|
267
279
|
var WorkflowStatus = /* @__PURE__ */ ((WorkflowStatus2) => {
|
|
@@ -640,6 +652,12 @@ var LoopExecutor = class {
|
|
|
640
652
|
} catch (e) {
|
|
641
653
|
throw new Error(`Loop block execute error`);
|
|
642
654
|
}
|
|
655
|
+
if (this.isBreak(subContext)) {
|
|
656
|
+
break;
|
|
657
|
+
}
|
|
658
|
+
if (this.isContinue(subContext)) {
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
643
661
|
const blockOutput = this.getBlockOutput(context, subContext);
|
|
644
662
|
blockOutputs.push(blockOutput);
|
|
645
663
|
}
|
|
@@ -723,69 +741,25 @@ var LoopExecutor = class {
|
|
|
723
741
|
const loopOutputsDeclare = loopNodeData.loopOutputs ?? {};
|
|
724
742
|
return loopOutputsDeclare;
|
|
725
743
|
}
|
|
744
|
+
isBreak(subContext) {
|
|
745
|
+
return subContext.cache.get("loop-break") === true;
|
|
746
|
+
}
|
|
747
|
+
isContinue(subContext) {
|
|
748
|
+
return subContext.cache.get("loop-continue") === true;
|
|
749
|
+
}
|
|
726
750
|
};
|
|
727
751
|
|
|
728
752
|
// src/nodes/llm/index.ts
|
|
729
753
|
var import_lodash_es2 = require("lodash-es");
|
|
730
754
|
var import_openai = require("@langchain/openai");
|
|
731
755
|
var import_messages = require("@langchain/core/messages");
|
|
732
|
-
|
|
733
|
-
// src/nodes/llm/api-validator.ts
|
|
734
|
-
var APIValidator;
|
|
735
|
-
((APIValidator2) => {
|
|
736
|
-
APIValidator2.isValidFormat = (apiHost) => {
|
|
737
|
-
if (!apiHost || typeof apiHost !== "string") {
|
|
738
|
-
return false;
|
|
739
|
-
}
|
|
740
|
-
try {
|
|
741
|
-
const url = new URL(apiHost);
|
|
742
|
-
return url.protocol === "http:" || url.protocol === "https:";
|
|
743
|
-
} catch (error) {
|
|
744
|
-
return false;
|
|
745
|
-
}
|
|
746
|
-
};
|
|
747
|
-
APIValidator2.isExist = async (apiHost) => {
|
|
748
|
-
try {
|
|
749
|
-
const controller = new AbortController();
|
|
750
|
-
const timeoutId = setTimeout(() => controller.abort(), 5e3);
|
|
751
|
-
await fetch(apiHost, {
|
|
752
|
-
method: "HEAD",
|
|
753
|
-
// Use HEAD to minimize data transfer
|
|
754
|
-
signal: controller.signal,
|
|
755
|
-
// Disable following redirects to get the actual host response
|
|
756
|
-
redirect: "manual"
|
|
757
|
-
});
|
|
758
|
-
clearTimeout(timeoutId);
|
|
759
|
-
return true;
|
|
760
|
-
} catch (error) {
|
|
761
|
-
if (error.name === "AbortError") {
|
|
762
|
-
return false;
|
|
763
|
-
}
|
|
764
|
-
const errorMessage = error.message?.toLowerCase() || "";
|
|
765
|
-
const networkFailurePatterns = [
|
|
766
|
-
"network error",
|
|
767
|
-
"connection refused",
|
|
768
|
-
"dns",
|
|
769
|
-
"resolve",
|
|
770
|
-
"timeout",
|
|
771
|
-
"unreachable"
|
|
772
|
-
];
|
|
773
|
-
const isNetworkFailure = networkFailurePatterns.some(
|
|
774
|
-
(pattern) => errorMessage.includes(pattern)
|
|
775
|
-
);
|
|
776
|
-
return !isNetworkFailure;
|
|
777
|
-
}
|
|
778
|
-
};
|
|
779
|
-
})(APIValidator || (APIValidator = {}));
|
|
780
|
-
|
|
781
|
-
// src/nodes/llm/index.ts
|
|
782
756
|
var LLMExecutor = class {
|
|
783
757
|
constructor() {
|
|
784
758
|
this.type = FlowGramNode.LLM;
|
|
785
759
|
}
|
|
786
760
|
async execute(context) {
|
|
787
761
|
const inputs = context.inputs;
|
|
788
|
-
|
|
762
|
+
this.checkInputs(inputs);
|
|
789
763
|
const { modelName, temperature, apiKey, apiHost, systemPrompt, prompt } = inputs;
|
|
790
764
|
const model = new import_openai.ChatOpenAI({
|
|
791
765
|
modelName,
|
|
@@ -793,7 +767,8 @@ var LLMExecutor = class {
|
|
|
793
767
|
apiKey,
|
|
794
768
|
configuration: {
|
|
795
769
|
baseURL: apiHost
|
|
796
|
-
}
|
|
770
|
+
},
|
|
771
|
+
maxRetries: 3
|
|
797
772
|
});
|
|
798
773
|
const messages = [];
|
|
799
774
|
if (systemPrompt) {
|
|
@@ -817,7 +792,7 @@ var LLMExecutor = class {
|
|
|
817
792
|
}
|
|
818
793
|
};
|
|
819
794
|
}
|
|
820
|
-
|
|
795
|
+
checkInputs(inputs) {
|
|
821
796
|
const { modelName, temperature, apiKey, apiHost, prompt } = inputs;
|
|
822
797
|
const missingInputs = [];
|
|
823
798
|
if (!modelName) missingInputs.push("modelName");
|
|
@@ -828,12 +803,236 @@ var LLMExecutor = class {
|
|
|
828
803
|
if (missingInputs.length > 0) {
|
|
829
804
|
throw new Error(`LLM node missing required inputs: "${missingInputs.join('", "')}"`);
|
|
830
805
|
}
|
|
831
|
-
|
|
806
|
+
this.checkApiHost(apiHost);
|
|
807
|
+
}
|
|
808
|
+
checkApiHost(apiHost) {
|
|
809
|
+
if (!apiHost || typeof apiHost !== "string") {
|
|
832
810
|
throw new Error(`Invalid API host format - ${apiHost}`);
|
|
833
811
|
}
|
|
834
|
-
const
|
|
835
|
-
if (
|
|
836
|
-
throw new Error(`
|
|
812
|
+
const url = new URL(apiHost);
|
|
813
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
814
|
+
throw new Error(`Invalid API host protocol - ${url.protocol}`);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
// src/nodes/http/index.ts
|
|
820
|
+
var HTTPExecutor = class {
|
|
821
|
+
constructor() {
|
|
822
|
+
this.type = FlowGramNode.HTTP;
|
|
823
|
+
}
|
|
824
|
+
async execute(context) {
|
|
825
|
+
const inputs = this.parseInputs(context);
|
|
826
|
+
const response = await this.request(inputs);
|
|
827
|
+
const responseHeaders = {};
|
|
828
|
+
response.headers.forEach((value, key) => {
|
|
829
|
+
responseHeaders[key] = value;
|
|
830
|
+
});
|
|
831
|
+
const responseBody = await response.text();
|
|
832
|
+
return {
|
|
833
|
+
outputs: {
|
|
834
|
+
headers: responseHeaders,
|
|
835
|
+
statusCode: response.status,
|
|
836
|
+
body: responseBody
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
async request(inputs) {
|
|
841
|
+
const { method, url, headers, params, bodyType, body, retryTimes, timeout } = inputs;
|
|
842
|
+
const urlWithParams = this.buildUrlWithParams(url, params);
|
|
843
|
+
const requestOptions = {
|
|
844
|
+
method,
|
|
845
|
+
headers: this.prepareHeaders(headers, bodyType),
|
|
846
|
+
signal: AbortSignal.timeout(timeout)
|
|
847
|
+
};
|
|
848
|
+
if (method !== "GET" && method !== "HEAD" && body) {
|
|
849
|
+
requestOptions.body = this.prepareBody(body, bodyType);
|
|
850
|
+
}
|
|
851
|
+
let lastError = null;
|
|
852
|
+
for (let attempt = 0; attempt <= retryTimes; attempt++) {
|
|
853
|
+
try {
|
|
854
|
+
const response = await fetch(urlWithParams, requestOptions);
|
|
855
|
+
return response;
|
|
856
|
+
} catch (error) {
|
|
857
|
+
lastError = error;
|
|
858
|
+
if (attempt < retryTimes) {
|
|
859
|
+
await new Promise((resolve) => setTimeout(resolve, Math.pow(2, attempt) * 1e3));
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
throw lastError || new Error("HTTP request failed after all retry attempts");
|
|
864
|
+
}
|
|
865
|
+
parseInputs(context) {
|
|
866
|
+
const httpNode = context.node;
|
|
867
|
+
const method = httpNode.data.api.method;
|
|
868
|
+
const urlVariable = context.runtime.state.parseTemplate(httpNode.data.api.url);
|
|
869
|
+
if (!urlVariable) {
|
|
870
|
+
throw new Error("HTTP url is required");
|
|
871
|
+
}
|
|
872
|
+
const url = urlVariable.value;
|
|
873
|
+
const headers = context.runtime.state.parseInputs({
|
|
874
|
+
values: httpNode.data.headersValues,
|
|
875
|
+
declare: httpNode.data.headers
|
|
876
|
+
});
|
|
877
|
+
const params = context.runtime.state.parseInputs({
|
|
878
|
+
values: httpNode.data.paramsValues,
|
|
879
|
+
declare: httpNode.data.params
|
|
880
|
+
});
|
|
881
|
+
const body = this.parseBody(context);
|
|
882
|
+
const retryTimes = httpNode.data.timeout.retryTimes;
|
|
883
|
+
const timeout = httpNode.data.timeout.timeout;
|
|
884
|
+
const inputs = {
|
|
885
|
+
method,
|
|
886
|
+
url,
|
|
887
|
+
headers,
|
|
888
|
+
params,
|
|
889
|
+
bodyType: body.bodyType,
|
|
890
|
+
body: body.body,
|
|
891
|
+
retryTimes,
|
|
892
|
+
timeout
|
|
893
|
+
};
|
|
894
|
+
context.snapshot.update({
|
|
895
|
+
inputs: JSON.parse(JSON.stringify(inputs))
|
|
896
|
+
});
|
|
897
|
+
return inputs;
|
|
898
|
+
}
|
|
899
|
+
parseBody(context) {
|
|
900
|
+
const httpNode = context.node;
|
|
901
|
+
const bodyType = httpNode.data.body.bodyType;
|
|
902
|
+
if (bodyType === HTTPBodyType.None) {
|
|
903
|
+
return {
|
|
904
|
+
bodyType,
|
|
905
|
+
body: ""
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
if (bodyType === HTTPBodyType.JSON) {
|
|
909
|
+
if (!httpNode.data.body.json) {
|
|
910
|
+
throw new Error("HTTP json body is required");
|
|
911
|
+
}
|
|
912
|
+
const jsonVariable = context.runtime.state.parseTemplate(httpNode.data.body.json);
|
|
913
|
+
if (!jsonVariable) {
|
|
914
|
+
throw new Error("HTTP json body is required");
|
|
915
|
+
}
|
|
916
|
+
return {
|
|
917
|
+
bodyType,
|
|
918
|
+
body: jsonVariable.value
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
if (bodyType === HTTPBodyType.FormData) {
|
|
922
|
+
if (!httpNode.data.body.formData || !httpNode.data.body.formDataValues) {
|
|
923
|
+
throw new Error("HTTP form-data body is required");
|
|
924
|
+
}
|
|
925
|
+
const formData = context.runtime.state.parseInputs({
|
|
926
|
+
values: httpNode.data.body.formDataValues,
|
|
927
|
+
declare: httpNode.data.body.formData
|
|
928
|
+
});
|
|
929
|
+
return {
|
|
930
|
+
bodyType,
|
|
931
|
+
body: JSON.stringify(formData)
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
if (bodyType === HTTPBodyType.RawText) {
|
|
935
|
+
if (!httpNode.data.body.json) {
|
|
936
|
+
throw new Error("HTTP json body is required");
|
|
937
|
+
}
|
|
938
|
+
const jsonVariable = context.runtime.state.parseTemplate(httpNode.data.body.json);
|
|
939
|
+
if (!jsonVariable) {
|
|
940
|
+
throw new Error("HTTP json body is required");
|
|
941
|
+
}
|
|
942
|
+
return {
|
|
943
|
+
bodyType,
|
|
944
|
+
body: jsonVariable.value
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
if (bodyType === HTTPBodyType.Binary) {
|
|
948
|
+
if (!httpNode.data.body.binary) {
|
|
949
|
+
throw new Error("HTTP binary body is required");
|
|
950
|
+
}
|
|
951
|
+
const binaryVariable = context.runtime.state.parseTemplate(httpNode.data.body.binary);
|
|
952
|
+
if (!binaryVariable) {
|
|
953
|
+
throw new Error("HTTP binary body is required");
|
|
954
|
+
}
|
|
955
|
+
return {
|
|
956
|
+
bodyType,
|
|
957
|
+
body: binaryVariable.value
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
if (bodyType === HTTPBodyType.XWwwFormUrlencoded) {
|
|
961
|
+
if (!httpNode.data.body.xWwwFormUrlencoded || !httpNode.data.body.xWwwFormUrlencodedValues) {
|
|
962
|
+
throw new Error("HTTP x-www-form-urlencoded body is required");
|
|
963
|
+
}
|
|
964
|
+
const xWwwFormUrlencoded = context.runtime.state.parseInputs({
|
|
965
|
+
values: httpNode.data.body.xWwwFormUrlencodedValues,
|
|
966
|
+
declare: httpNode.data.body.xWwwFormUrlencoded
|
|
967
|
+
});
|
|
968
|
+
return {
|
|
969
|
+
bodyType,
|
|
970
|
+
body: JSON.stringify(xWwwFormUrlencoded)
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
throw new Error(`HTTP invalid body type "${bodyType}"`);
|
|
974
|
+
}
|
|
975
|
+
buildUrlWithParams(url, params) {
|
|
976
|
+
const urlObj = new URL(url);
|
|
977
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
978
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
979
|
+
urlObj.searchParams.set(key, value);
|
|
980
|
+
}
|
|
981
|
+
});
|
|
982
|
+
return urlObj.toString();
|
|
983
|
+
}
|
|
984
|
+
prepareHeaders(headers, bodyType) {
|
|
985
|
+
const preparedHeaders = { ...headers };
|
|
986
|
+
if (!preparedHeaders["Content-Type"] && !preparedHeaders["content-type"]) {
|
|
987
|
+
switch (bodyType) {
|
|
988
|
+
case HTTPBodyType.JSON:
|
|
989
|
+
preparedHeaders["Content-Type"] = "application/json";
|
|
990
|
+
break;
|
|
991
|
+
case HTTPBodyType.FormData:
|
|
992
|
+
break;
|
|
993
|
+
case HTTPBodyType.XWwwFormUrlencoded:
|
|
994
|
+
preparedHeaders["Content-Type"] = "application/x-www-form-urlencoded";
|
|
995
|
+
break;
|
|
996
|
+
case HTTPBodyType.RawText:
|
|
997
|
+
preparedHeaders["Content-Type"] = "text/plain";
|
|
998
|
+
break;
|
|
999
|
+
case HTTPBodyType.Binary:
|
|
1000
|
+
preparedHeaders["Content-Type"] = "application/octet-stream";
|
|
1001
|
+
break;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
return preparedHeaders;
|
|
1005
|
+
}
|
|
1006
|
+
prepareBody(body, bodyType) {
|
|
1007
|
+
switch (bodyType) {
|
|
1008
|
+
case HTTPBodyType.JSON:
|
|
1009
|
+
return body;
|
|
1010
|
+
case HTTPBodyType.FormData:
|
|
1011
|
+
const formData = new FormData();
|
|
1012
|
+
try {
|
|
1013
|
+
const data = JSON.parse(body);
|
|
1014
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
1015
|
+
formData.append(key, String(value));
|
|
1016
|
+
});
|
|
1017
|
+
} catch (error) {
|
|
1018
|
+
throw new Error("Invalid FormData body format");
|
|
1019
|
+
}
|
|
1020
|
+
return formData;
|
|
1021
|
+
case HTTPBodyType.XWwwFormUrlencoded:
|
|
1022
|
+
try {
|
|
1023
|
+
const data = JSON.parse(body);
|
|
1024
|
+
const params = new URLSearchParams();
|
|
1025
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
1026
|
+
params.append(key, String(value));
|
|
1027
|
+
});
|
|
1028
|
+
return params.toString();
|
|
1029
|
+
} catch (error) {
|
|
1030
|
+
throw new Error("Invalid x-www-form-urlencoded body format");
|
|
1031
|
+
}
|
|
1032
|
+
case HTTPBodyType.RawText:
|
|
1033
|
+
case HTTPBodyType.Binary:
|
|
1034
|
+
default:
|
|
1035
|
+
return body;
|
|
837
1036
|
}
|
|
838
1037
|
}
|
|
839
1038
|
};
|
|
@@ -873,6 +1072,19 @@ var BlockEndExecutor = class {
|
|
|
873
1072
|
}
|
|
874
1073
|
};
|
|
875
1074
|
|
|
1075
|
+
// src/nodes/continue/index.ts
|
|
1076
|
+
var ContinueExecutor = class {
|
|
1077
|
+
constructor() {
|
|
1078
|
+
this.type = FlowGramNode.Continue;
|
|
1079
|
+
}
|
|
1080
|
+
async execute(context) {
|
|
1081
|
+
context.runtime.cache.set("loop-continue", true);
|
|
1082
|
+
return {
|
|
1083
|
+
outputs: {}
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
};
|
|
1087
|
+
|
|
876
1088
|
// src/nodes/condition/index.ts
|
|
877
1089
|
var import_lodash_es9 = require("lodash-es");
|
|
878
1090
|
|
|
@@ -1164,7 +1376,7 @@ var ConditionExecutor = class {
|
|
|
1164
1376
|
`Condition left type "${condition.leftType}" has no operator "${condition.operator}"`
|
|
1165
1377
|
);
|
|
1166
1378
|
}
|
|
1167
|
-
if (ruleType
|
|
1379
|
+
if (!WorkflowRuntimeType.isTypeEqual(ruleType, condition.rightType)) {
|
|
1168
1380
|
return false;
|
|
1169
1381
|
}
|
|
1170
1382
|
return true;
|
|
@@ -1179,6 +1391,81 @@ var ConditionExecutor = class {
|
|
|
1179
1391
|
}
|
|
1180
1392
|
};
|
|
1181
1393
|
|
|
1394
|
+
// src/nodes/code/index.ts
|
|
1395
|
+
var CodeExecutor = class {
|
|
1396
|
+
constructor() {
|
|
1397
|
+
this.type = FlowGramNode.Code;
|
|
1398
|
+
}
|
|
1399
|
+
async execute(context) {
|
|
1400
|
+
const inputs = this.parseInputs(context);
|
|
1401
|
+
if (inputs.script.language === "javascript") {
|
|
1402
|
+
return this.javascript(inputs);
|
|
1403
|
+
}
|
|
1404
|
+
throw new Error(`Unsupported code language "${inputs.script.language}"`);
|
|
1405
|
+
}
|
|
1406
|
+
parseInputs(context) {
|
|
1407
|
+
const codeNode = context.node;
|
|
1408
|
+
const params = context.inputs;
|
|
1409
|
+
const { language, content } = codeNode.data.script;
|
|
1410
|
+
if (!content) {
|
|
1411
|
+
throw new Error("Code content is required");
|
|
1412
|
+
}
|
|
1413
|
+
return {
|
|
1414
|
+
params,
|
|
1415
|
+
script: {
|
|
1416
|
+
language,
|
|
1417
|
+
content
|
|
1418
|
+
}
|
|
1419
|
+
};
|
|
1420
|
+
}
|
|
1421
|
+
async javascript(inputs) {
|
|
1422
|
+
const { params = {}, script } = inputs;
|
|
1423
|
+
try {
|
|
1424
|
+
const executeCode = new Function(
|
|
1425
|
+
"params",
|
|
1426
|
+
`
|
|
1427
|
+
'use strict';
|
|
1428
|
+
|
|
1429
|
+
${script.content}
|
|
1430
|
+
|
|
1431
|
+
// Ensure main function exists
|
|
1432
|
+
if (typeof main !== 'function') {
|
|
1433
|
+
throw new Error('main function is required in the script');
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
// Execute main function with params
|
|
1437
|
+
return main({ params });
|
|
1438
|
+
`
|
|
1439
|
+
);
|
|
1440
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1441
|
+
setTimeout(() => {
|
|
1442
|
+
reject(new Error("Code execution timeout: exceeded 1 minute"));
|
|
1443
|
+
}, 1e3 * 60);
|
|
1444
|
+
});
|
|
1445
|
+
const result = await Promise.race([executeCode(params), timeoutPromise]);
|
|
1446
|
+
const outputs = result && typeof result === "object" && !Array.isArray(result) ? result : { result };
|
|
1447
|
+
return {
|
|
1448
|
+
outputs
|
|
1449
|
+
};
|
|
1450
|
+
} catch (error) {
|
|
1451
|
+
throw new Error(`Code execution failed: ${error.message}`);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
};
|
|
1455
|
+
|
|
1456
|
+
// src/nodes/break/index.ts
|
|
1457
|
+
var BreakExecutor = class {
|
|
1458
|
+
constructor() {
|
|
1459
|
+
this.type = FlowGramNode.Break;
|
|
1460
|
+
}
|
|
1461
|
+
async execute(context) {
|
|
1462
|
+
context.runtime.cache.set("loop-break", true);
|
|
1463
|
+
return {
|
|
1464
|
+
outputs: {}
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1467
|
+
};
|
|
1468
|
+
|
|
1182
1469
|
// src/nodes/index.ts
|
|
1183
1470
|
var WorkflowRuntimeNodeExecutors = [
|
|
1184
1471
|
StartExecutor,
|
|
@@ -1187,7 +1474,11 @@ var WorkflowRuntimeNodeExecutors = [
|
|
|
1187
1474
|
ConditionExecutor,
|
|
1188
1475
|
LoopExecutor,
|
|
1189
1476
|
BlockStartExecutor,
|
|
1190
|
-
BlockEndExecutor
|
|
1477
|
+
BlockEndExecutor,
|
|
1478
|
+
HTTPExecutor,
|
|
1479
|
+
CodeExecutor,
|
|
1480
|
+
BreakExecutor,
|
|
1481
|
+
ContinueExecutor
|
|
1191
1482
|
];
|
|
1192
1483
|
|
|
1193
1484
|
// src/domain/validation/validators/cycle-detection.ts
|
|
@@ -1606,6 +1897,29 @@ var WorkflowRuntimeMessageCenter = class {
|
|
|
1606
1897
|
}
|
|
1607
1898
|
};
|
|
1608
1899
|
|
|
1900
|
+
// src/domain/cache/index.ts
|
|
1901
|
+
var WorkflowRuntimeCache = class {
|
|
1902
|
+
init() {
|
|
1903
|
+
this.map = /* @__PURE__ */ new Map();
|
|
1904
|
+
}
|
|
1905
|
+
dispose() {
|
|
1906
|
+
this.map.clear();
|
|
1907
|
+
}
|
|
1908
|
+
get(key) {
|
|
1909
|
+
return this.map.get(key);
|
|
1910
|
+
}
|
|
1911
|
+
set(key, value) {
|
|
1912
|
+
this.map.set(key, value);
|
|
1913
|
+
return this;
|
|
1914
|
+
}
|
|
1915
|
+
delete(key) {
|
|
1916
|
+
return this.map.delete(key);
|
|
1917
|
+
}
|
|
1918
|
+
has(key) {
|
|
1919
|
+
return this.map.has(key);
|
|
1920
|
+
}
|
|
1921
|
+
};
|
|
1922
|
+
|
|
1609
1923
|
// src/domain/variable/variable-store/index.ts
|
|
1610
1924
|
var import_lodash_es10 = require("lodash-es");
|
|
1611
1925
|
|
|
@@ -1831,26 +2145,10 @@ var WorkflowRuntimeState = class {
|
|
|
1831
2145
|
getNodeInputs(node) {
|
|
1832
2146
|
const inputsDeclare = node.declare.inputs;
|
|
1833
2147
|
const inputsValues = node.declare.inputsValues;
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
const typeInfo = inputsDeclare.properties?.[key];
|
|
1839
|
-
if (!typeInfo) {
|
|
1840
|
-
return prev;
|
|
1841
|
-
}
|
|
1842
|
-
const expectType = typeInfo.type;
|
|
1843
|
-
const result = this.parseValue(inputValue);
|
|
1844
|
-
if (!result) {
|
|
1845
|
-
return prev;
|
|
1846
|
-
}
|
|
1847
|
-
const { value, type } = result;
|
|
1848
|
-
if (!WorkflowRuntimeType.isTypeEqual(type, expectType)) {
|
|
1849
|
-
return prev;
|
|
1850
|
-
}
|
|
1851
|
-
prev[key] = value;
|
|
1852
|
-
return prev;
|
|
1853
|
-
}, {});
|
|
2148
|
+
return this.parseInputs({
|
|
2149
|
+
values: inputsValues,
|
|
2150
|
+
declare: inputsDeclare
|
|
2151
|
+
});
|
|
1854
2152
|
}
|
|
1855
2153
|
setNodeOutputs(params) {
|
|
1856
2154
|
const { node, outputs } = params;
|
|
@@ -1874,6 +2172,29 @@ var WorkflowRuntimeState = class {
|
|
|
1874
2172
|
});
|
|
1875
2173
|
});
|
|
1876
2174
|
}
|
|
2175
|
+
parseInputs(params) {
|
|
2176
|
+
const { values, declare } = params;
|
|
2177
|
+
if (!declare || !values) {
|
|
2178
|
+
return {};
|
|
2179
|
+
}
|
|
2180
|
+
return Object.entries(values).reduce((prev, [key, inputValue]) => {
|
|
2181
|
+
const typeInfo = declare.properties?.[key];
|
|
2182
|
+
if (!typeInfo) {
|
|
2183
|
+
return prev;
|
|
2184
|
+
}
|
|
2185
|
+
const expectType = typeInfo.type;
|
|
2186
|
+
const result = this.parseValue(inputValue);
|
|
2187
|
+
if (!result) {
|
|
2188
|
+
return prev;
|
|
2189
|
+
}
|
|
2190
|
+
const { value, type } = result;
|
|
2191
|
+
if (!WorkflowRuntimeType.isTypeEqual(type, expectType)) {
|
|
2192
|
+
return prev;
|
|
2193
|
+
}
|
|
2194
|
+
prev[key] = value;
|
|
2195
|
+
return prev;
|
|
2196
|
+
}, {});
|
|
2197
|
+
}
|
|
1877
2198
|
parseRef(ref) {
|
|
1878
2199
|
if (ref?.type !== "ref") {
|
|
1879
2200
|
throw new Error(`Invalid ref value: ${ref}`);
|
|
@@ -2407,6 +2728,7 @@ var WorkflowRuntimeContext = class _WorkflowRuntimeContext {
|
|
|
2407
2728
|
constructor(data) {
|
|
2408
2729
|
this.subContexts = [];
|
|
2409
2730
|
this.id = uuid();
|
|
2731
|
+
this.cache = data.cache;
|
|
2410
2732
|
this.document = data.document;
|
|
2411
2733
|
this.variableStore = data.variableStore;
|
|
2412
2734
|
this.state = data.state;
|
|
@@ -2418,6 +2740,7 @@ var WorkflowRuntimeContext = class _WorkflowRuntimeContext {
|
|
|
2418
2740
|
}
|
|
2419
2741
|
init(params) {
|
|
2420
2742
|
const { schema, inputs } = params;
|
|
2743
|
+
this.cache.init();
|
|
2421
2744
|
this.document.init(schema);
|
|
2422
2745
|
this.variableStore.init();
|
|
2423
2746
|
this.state.init();
|
|
@@ -2432,6 +2755,7 @@ var WorkflowRuntimeContext = class _WorkflowRuntimeContext {
|
|
|
2432
2755
|
subContext.dispose();
|
|
2433
2756
|
});
|
|
2434
2757
|
this.subContexts = [];
|
|
2758
|
+
this.cache.dispose();
|
|
2435
2759
|
this.document.dispose();
|
|
2436
2760
|
this.variableStore.dispose();
|
|
2437
2761
|
this.state.dispose();
|
|
@@ -2442,10 +2766,12 @@ var WorkflowRuntimeContext = class _WorkflowRuntimeContext {
|
|
|
2442
2766
|
this.reporter.dispose();
|
|
2443
2767
|
}
|
|
2444
2768
|
sub() {
|
|
2769
|
+
const cache = new WorkflowRuntimeCache();
|
|
2445
2770
|
const variableStore = new WorkflowRuntimeVariableStore();
|
|
2446
2771
|
variableStore.setParent(this.variableStore);
|
|
2447
2772
|
const state = new WorkflowRuntimeState(variableStore);
|
|
2448
2773
|
const contextData = {
|
|
2774
|
+
cache,
|
|
2449
2775
|
document: this.document,
|
|
2450
2776
|
ioCenter: this.ioCenter,
|
|
2451
2777
|
snapshotCenter: this.snapshotCenter,
|
|
@@ -2457,11 +2783,13 @@ var WorkflowRuntimeContext = class _WorkflowRuntimeContext {
|
|
|
2457
2783
|
};
|
|
2458
2784
|
const subContext = new _WorkflowRuntimeContext(contextData);
|
|
2459
2785
|
this.subContexts.push(subContext);
|
|
2786
|
+
subContext.cache.init();
|
|
2460
2787
|
subContext.variableStore.init();
|
|
2461
2788
|
subContext.state.init();
|
|
2462
2789
|
return subContext;
|
|
2463
2790
|
}
|
|
2464
2791
|
static create() {
|
|
2792
|
+
const cache = new WorkflowRuntimeCache();
|
|
2465
2793
|
const document = new WorkflowRuntimeDocument();
|
|
2466
2794
|
const variableStore = new WorkflowRuntimeVariableStore();
|
|
2467
2795
|
const state = new WorkflowRuntimeState(variableStore);
|
|
@@ -2476,6 +2804,7 @@ var WorkflowRuntimeContext = class _WorkflowRuntimeContext {
|
|
|
2476
2804
|
messageCenter
|
|
2477
2805
|
);
|
|
2478
2806
|
return new _WorkflowRuntimeContext({
|
|
2807
|
+
cache,
|
|
2479
2808
|
document,
|
|
2480
2809
|
variableStore,
|
|
2481
2810
|
state,
|
|
@@ -2533,7 +2862,8 @@ var WorkflowRuntimeEngine = class {
|
|
|
2533
2862
|
node,
|
|
2534
2863
|
inputs,
|
|
2535
2864
|
runtime: context,
|
|
2536
|
-
container: WorkflowRuntimeContainer.instance
|
|
2865
|
+
container: WorkflowRuntimeContainer.instance,
|
|
2866
|
+
snapshot
|
|
2537
2867
|
});
|
|
2538
2868
|
if (context.statusCenter.workflow.terminated) {
|
|
2539
2869
|
return;
|
|
@@ -2614,7 +2944,13 @@ var WorkflowRuntimeEngine = class {
|
|
|
2614
2944
|
}
|
|
2615
2945
|
async executeNext(params) {
|
|
2616
2946
|
const { context, node, nextNodes } = params;
|
|
2617
|
-
|
|
2947
|
+
const terminatingNodeTypes = [
|
|
2948
|
+
FlowGramNode.End,
|
|
2949
|
+
FlowGramNode.BlockEnd,
|
|
2950
|
+
FlowGramNode.Break,
|
|
2951
|
+
FlowGramNode.Continue
|
|
2952
|
+
];
|
|
2953
|
+
if (terminatingNodeTypes.includes(node.type)) {
|
|
2618
2954
|
return;
|
|
2619
2955
|
}
|
|
2620
2956
|
if (nextNodes.length === 0) {
|