@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/esm/index.js
CHANGED
|
@@ -195,13 +195,16 @@ var FlowGramNode = /* @__PURE__ */ ((FlowGramNode22) => {
|
|
|
195
195
|
FlowGramNode22["Start"] = "start";
|
|
196
196
|
FlowGramNode22["End"] = "end";
|
|
197
197
|
FlowGramNode22["LLM"] = "llm";
|
|
198
|
-
FlowGramNode22["
|
|
198
|
+
FlowGramNode22["Code"] = "code";
|
|
199
199
|
FlowGramNode22["Condition"] = "condition";
|
|
200
200
|
FlowGramNode22["Loop"] = "loop";
|
|
201
201
|
FlowGramNode22["Comment"] = "comment";
|
|
202
202
|
FlowGramNode22["Group"] = "group";
|
|
203
203
|
FlowGramNode22["BlockStart"] = "block-start";
|
|
204
204
|
FlowGramNode22["BlockEnd"] = "block-end";
|
|
205
|
+
FlowGramNode22["HTTP"] = "http";
|
|
206
|
+
FlowGramNode22["Break"] = "break";
|
|
207
|
+
FlowGramNode22["Continue"] = "continue";
|
|
205
208
|
return FlowGramNode22;
|
|
206
209
|
})(FlowGramNode || {});
|
|
207
210
|
var ConditionOperation = /* @__PURE__ */ ((ConditionOperation2) => {
|
|
@@ -221,6 +224,15 @@ var ConditionOperation = /* @__PURE__ */ ((ConditionOperation2) => {
|
|
|
221
224
|
ConditionOperation2["IS_FALSE"] = "is_false";
|
|
222
225
|
return ConditionOperation2;
|
|
223
226
|
})(ConditionOperation || {});
|
|
227
|
+
var HTTPBodyType = /* @__PURE__ */ ((HTTPBodyType2) => {
|
|
228
|
+
HTTPBodyType2["None"] = "none";
|
|
229
|
+
HTTPBodyType2["FormData"] = "form-data";
|
|
230
|
+
HTTPBodyType2["XWwwFormUrlencoded"] = "x-www-form-urlencoded";
|
|
231
|
+
HTTPBodyType2["RawText"] = "raw-text";
|
|
232
|
+
HTTPBodyType2["JSON"] = "JSON";
|
|
233
|
+
HTTPBodyType2["Binary"] = "binary";
|
|
234
|
+
return HTTPBodyType2;
|
|
235
|
+
})(HTTPBodyType || {});
|
|
224
236
|
var IEngine = Symbol.for("Engine");
|
|
225
237
|
var IExecutor = Symbol.for("Executor");
|
|
226
238
|
var WorkflowStatus = /* @__PURE__ */ ((WorkflowStatus2) => {
|
|
@@ -599,6 +611,12 @@ var LoopExecutor = class {
|
|
|
599
611
|
} catch (e) {
|
|
600
612
|
throw new Error(`Loop block execute error`);
|
|
601
613
|
}
|
|
614
|
+
if (this.isBreak(subContext)) {
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
if (this.isContinue(subContext)) {
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
602
620
|
const blockOutput = this.getBlockOutput(context, subContext);
|
|
603
621
|
blockOutputs.push(blockOutput);
|
|
604
622
|
}
|
|
@@ -682,69 +700,25 @@ var LoopExecutor = class {
|
|
|
682
700
|
const loopOutputsDeclare = loopNodeData.loopOutputs ?? {};
|
|
683
701
|
return loopOutputsDeclare;
|
|
684
702
|
}
|
|
703
|
+
isBreak(subContext) {
|
|
704
|
+
return subContext.cache.get("loop-break") === true;
|
|
705
|
+
}
|
|
706
|
+
isContinue(subContext) {
|
|
707
|
+
return subContext.cache.get("loop-continue") === true;
|
|
708
|
+
}
|
|
685
709
|
};
|
|
686
710
|
|
|
687
711
|
// src/nodes/llm/index.ts
|
|
688
712
|
import { isNil as isNil2 } from "lodash-es";
|
|
689
713
|
import { ChatOpenAI } from "@langchain/openai";
|
|
690
714
|
import { SystemMessage, HumanMessage } from "@langchain/core/messages";
|
|
691
|
-
|
|
692
|
-
// src/nodes/llm/api-validator.ts
|
|
693
|
-
var APIValidator;
|
|
694
|
-
((APIValidator2) => {
|
|
695
|
-
APIValidator2.isValidFormat = (apiHost) => {
|
|
696
|
-
if (!apiHost || typeof apiHost !== "string") {
|
|
697
|
-
return false;
|
|
698
|
-
}
|
|
699
|
-
try {
|
|
700
|
-
const url = new URL(apiHost);
|
|
701
|
-
return url.protocol === "http:" || url.protocol === "https:";
|
|
702
|
-
} catch (error) {
|
|
703
|
-
return false;
|
|
704
|
-
}
|
|
705
|
-
};
|
|
706
|
-
APIValidator2.isExist = async (apiHost) => {
|
|
707
|
-
try {
|
|
708
|
-
const controller = new AbortController();
|
|
709
|
-
const timeoutId = setTimeout(() => controller.abort(), 5e3);
|
|
710
|
-
await fetch(apiHost, {
|
|
711
|
-
method: "HEAD",
|
|
712
|
-
// Use HEAD to minimize data transfer
|
|
713
|
-
signal: controller.signal,
|
|
714
|
-
// Disable following redirects to get the actual host response
|
|
715
|
-
redirect: "manual"
|
|
716
|
-
});
|
|
717
|
-
clearTimeout(timeoutId);
|
|
718
|
-
return true;
|
|
719
|
-
} catch (error) {
|
|
720
|
-
if (error.name === "AbortError") {
|
|
721
|
-
return false;
|
|
722
|
-
}
|
|
723
|
-
const errorMessage = error.message?.toLowerCase() || "";
|
|
724
|
-
const networkFailurePatterns = [
|
|
725
|
-
"network error",
|
|
726
|
-
"connection refused",
|
|
727
|
-
"dns",
|
|
728
|
-
"resolve",
|
|
729
|
-
"timeout",
|
|
730
|
-
"unreachable"
|
|
731
|
-
];
|
|
732
|
-
const isNetworkFailure = networkFailurePatterns.some(
|
|
733
|
-
(pattern) => errorMessage.includes(pattern)
|
|
734
|
-
);
|
|
735
|
-
return !isNetworkFailure;
|
|
736
|
-
}
|
|
737
|
-
};
|
|
738
|
-
})(APIValidator || (APIValidator = {}));
|
|
739
|
-
|
|
740
|
-
// src/nodes/llm/index.ts
|
|
741
715
|
var LLMExecutor = class {
|
|
742
716
|
constructor() {
|
|
743
717
|
this.type = FlowGramNode.LLM;
|
|
744
718
|
}
|
|
745
719
|
async execute(context) {
|
|
746
720
|
const inputs = context.inputs;
|
|
747
|
-
|
|
721
|
+
this.checkInputs(inputs);
|
|
748
722
|
const { modelName, temperature, apiKey, apiHost, systemPrompt, prompt } = inputs;
|
|
749
723
|
const model = new ChatOpenAI({
|
|
750
724
|
modelName,
|
|
@@ -752,7 +726,8 @@ var LLMExecutor = class {
|
|
|
752
726
|
apiKey,
|
|
753
727
|
configuration: {
|
|
754
728
|
baseURL: apiHost
|
|
755
|
-
}
|
|
729
|
+
},
|
|
730
|
+
maxRetries: 3
|
|
756
731
|
});
|
|
757
732
|
const messages = [];
|
|
758
733
|
if (systemPrompt) {
|
|
@@ -776,7 +751,7 @@ var LLMExecutor = class {
|
|
|
776
751
|
}
|
|
777
752
|
};
|
|
778
753
|
}
|
|
779
|
-
|
|
754
|
+
checkInputs(inputs) {
|
|
780
755
|
const { modelName, temperature, apiKey, apiHost, prompt } = inputs;
|
|
781
756
|
const missingInputs = [];
|
|
782
757
|
if (!modelName) missingInputs.push("modelName");
|
|
@@ -787,12 +762,236 @@ var LLMExecutor = class {
|
|
|
787
762
|
if (missingInputs.length > 0) {
|
|
788
763
|
throw new Error(`LLM node missing required inputs: "${missingInputs.join('", "')}"`);
|
|
789
764
|
}
|
|
790
|
-
|
|
765
|
+
this.checkApiHost(apiHost);
|
|
766
|
+
}
|
|
767
|
+
checkApiHost(apiHost) {
|
|
768
|
+
if (!apiHost || typeof apiHost !== "string") {
|
|
791
769
|
throw new Error(`Invalid API host format - ${apiHost}`);
|
|
792
770
|
}
|
|
793
|
-
const
|
|
794
|
-
if (
|
|
795
|
-
throw new Error(`
|
|
771
|
+
const url = new URL(apiHost);
|
|
772
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
773
|
+
throw new Error(`Invalid API host protocol - ${url.protocol}`);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
|
|
778
|
+
// src/nodes/http/index.ts
|
|
779
|
+
var HTTPExecutor = class {
|
|
780
|
+
constructor() {
|
|
781
|
+
this.type = FlowGramNode.HTTP;
|
|
782
|
+
}
|
|
783
|
+
async execute(context) {
|
|
784
|
+
const inputs = this.parseInputs(context);
|
|
785
|
+
const response = await this.request(inputs);
|
|
786
|
+
const responseHeaders = {};
|
|
787
|
+
response.headers.forEach((value, key) => {
|
|
788
|
+
responseHeaders[key] = value;
|
|
789
|
+
});
|
|
790
|
+
const responseBody = await response.text();
|
|
791
|
+
return {
|
|
792
|
+
outputs: {
|
|
793
|
+
headers: responseHeaders,
|
|
794
|
+
statusCode: response.status,
|
|
795
|
+
body: responseBody
|
|
796
|
+
}
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
async request(inputs) {
|
|
800
|
+
const { method, url, headers, params, bodyType, body, retryTimes, timeout } = inputs;
|
|
801
|
+
const urlWithParams = this.buildUrlWithParams(url, params);
|
|
802
|
+
const requestOptions = {
|
|
803
|
+
method,
|
|
804
|
+
headers: this.prepareHeaders(headers, bodyType),
|
|
805
|
+
signal: AbortSignal.timeout(timeout)
|
|
806
|
+
};
|
|
807
|
+
if (method !== "GET" && method !== "HEAD" && body) {
|
|
808
|
+
requestOptions.body = this.prepareBody(body, bodyType);
|
|
809
|
+
}
|
|
810
|
+
let lastError = null;
|
|
811
|
+
for (let attempt = 0; attempt <= retryTimes; attempt++) {
|
|
812
|
+
try {
|
|
813
|
+
const response = await fetch(urlWithParams, requestOptions);
|
|
814
|
+
return response;
|
|
815
|
+
} catch (error) {
|
|
816
|
+
lastError = error;
|
|
817
|
+
if (attempt < retryTimes) {
|
|
818
|
+
await new Promise((resolve) => setTimeout(resolve, Math.pow(2, attempt) * 1e3));
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
throw lastError || new Error("HTTP request failed after all retry attempts");
|
|
823
|
+
}
|
|
824
|
+
parseInputs(context) {
|
|
825
|
+
const httpNode = context.node;
|
|
826
|
+
const method = httpNode.data.api.method;
|
|
827
|
+
const urlVariable = context.runtime.state.parseTemplate(httpNode.data.api.url);
|
|
828
|
+
if (!urlVariable) {
|
|
829
|
+
throw new Error("HTTP url is required");
|
|
830
|
+
}
|
|
831
|
+
const url = urlVariable.value;
|
|
832
|
+
const headers = context.runtime.state.parseInputs({
|
|
833
|
+
values: httpNode.data.headersValues,
|
|
834
|
+
declare: httpNode.data.headers
|
|
835
|
+
});
|
|
836
|
+
const params = context.runtime.state.parseInputs({
|
|
837
|
+
values: httpNode.data.paramsValues,
|
|
838
|
+
declare: httpNode.data.params
|
|
839
|
+
});
|
|
840
|
+
const body = this.parseBody(context);
|
|
841
|
+
const retryTimes = httpNode.data.timeout.retryTimes;
|
|
842
|
+
const timeout = httpNode.data.timeout.timeout;
|
|
843
|
+
const inputs = {
|
|
844
|
+
method,
|
|
845
|
+
url,
|
|
846
|
+
headers,
|
|
847
|
+
params,
|
|
848
|
+
bodyType: body.bodyType,
|
|
849
|
+
body: body.body,
|
|
850
|
+
retryTimes,
|
|
851
|
+
timeout
|
|
852
|
+
};
|
|
853
|
+
context.snapshot.update({
|
|
854
|
+
inputs: JSON.parse(JSON.stringify(inputs))
|
|
855
|
+
});
|
|
856
|
+
return inputs;
|
|
857
|
+
}
|
|
858
|
+
parseBody(context) {
|
|
859
|
+
const httpNode = context.node;
|
|
860
|
+
const bodyType = httpNode.data.body.bodyType;
|
|
861
|
+
if (bodyType === HTTPBodyType.None) {
|
|
862
|
+
return {
|
|
863
|
+
bodyType,
|
|
864
|
+
body: ""
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
if (bodyType === HTTPBodyType.JSON) {
|
|
868
|
+
if (!httpNode.data.body.json) {
|
|
869
|
+
throw new Error("HTTP json body is required");
|
|
870
|
+
}
|
|
871
|
+
const jsonVariable = context.runtime.state.parseTemplate(httpNode.data.body.json);
|
|
872
|
+
if (!jsonVariable) {
|
|
873
|
+
throw new Error("HTTP json body is required");
|
|
874
|
+
}
|
|
875
|
+
return {
|
|
876
|
+
bodyType,
|
|
877
|
+
body: jsonVariable.value
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
if (bodyType === HTTPBodyType.FormData) {
|
|
881
|
+
if (!httpNode.data.body.formData || !httpNode.data.body.formDataValues) {
|
|
882
|
+
throw new Error("HTTP form-data body is required");
|
|
883
|
+
}
|
|
884
|
+
const formData = context.runtime.state.parseInputs({
|
|
885
|
+
values: httpNode.data.body.formDataValues,
|
|
886
|
+
declare: httpNode.data.body.formData
|
|
887
|
+
});
|
|
888
|
+
return {
|
|
889
|
+
bodyType,
|
|
890
|
+
body: JSON.stringify(formData)
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
if (bodyType === HTTPBodyType.RawText) {
|
|
894
|
+
if (!httpNode.data.body.json) {
|
|
895
|
+
throw new Error("HTTP json body is required");
|
|
896
|
+
}
|
|
897
|
+
const jsonVariable = context.runtime.state.parseTemplate(httpNode.data.body.json);
|
|
898
|
+
if (!jsonVariable) {
|
|
899
|
+
throw new Error("HTTP json body is required");
|
|
900
|
+
}
|
|
901
|
+
return {
|
|
902
|
+
bodyType,
|
|
903
|
+
body: jsonVariable.value
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
if (bodyType === HTTPBodyType.Binary) {
|
|
907
|
+
if (!httpNode.data.body.binary) {
|
|
908
|
+
throw new Error("HTTP binary body is required");
|
|
909
|
+
}
|
|
910
|
+
const binaryVariable = context.runtime.state.parseTemplate(httpNode.data.body.binary);
|
|
911
|
+
if (!binaryVariable) {
|
|
912
|
+
throw new Error("HTTP binary body is required");
|
|
913
|
+
}
|
|
914
|
+
return {
|
|
915
|
+
bodyType,
|
|
916
|
+
body: binaryVariable.value
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
if (bodyType === HTTPBodyType.XWwwFormUrlencoded) {
|
|
920
|
+
if (!httpNode.data.body.xWwwFormUrlencoded || !httpNode.data.body.xWwwFormUrlencodedValues) {
|
|
921
|
+
throw new Error("HTTP x-www-form-urlencoded body is required");
|
|
922
|
+
}
|
|
923
|
+
const xWwwFormUrlencoded = context.runtime.state.parseInputs({
|
|
924
|
+
values: httpNode.data.body.xWwwFormUrlencodedValues,
|
|
925
|
+
declare: httpNode.data.body.xWwwFormUrlencoded
|
|
926
|
+
});
|
|
927
|
+
return {
|
|
928
|
+
bodyType,
|
|
929
|
+
body: JSON.stringify(xWwwFormUrlencoded)
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
throw new Error(`HTTP invalid body type "${bodyType}"`);
|
|
933
|
+
}
|
|
934
|
+
buildUrlWithParams(url, params) {
|
|
935
|
+
const urlObj = new URL(url);
|
|
936
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
937
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
938
|
+
urlObj.searchParams.set(key, value);
|
|
939
|
+
}
|
|
940
|
+
});
|
|
941
|
+
return urlObj.toString();
|
|
942
|
+
}
|
|
943
|
+
prepareHeaders(headers, bodyType) {
|
|
944
|
+
const preparedHeaders = { ...headers };
|
|
945
|
+
if (!preparedHeaders["Content-Type"] && !preparedHeaders["content-type"]) {
|
|
946
|
+
switch (bodyType) {
|
|
947
|
+
case HTTPBodyType.JSON:
|
|
948
|
+
preparedHeaders["Content-Type"] = "application/json";
|
|
949
|
+
break;
|
|
950
|
+
case HTTPBodyType.FormData:
|
|
951
|
+
break;
|
|
952
|
+
case HTTPBodyType.XWwwFormUrlencoded:
|
|
953
|
+
preparedHeaders["Content-Type"] = "application/x-www-form-urlencoded";
|
|
954
|
+
break;
|
|
955
|
+
case HTTPBodyType.RawText:
|
|
956
|
+
preparedHeaders["Content-Type"] = "text/plain";
|
|
957
|
+
break;
|
|
958
|
+
case HTTPBodyType.Binary:
|
|
959
|
+
preparedHeaders["Content-Type"] = "application/octet-stream";
|
|
960
|
+
break;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
return preparedHeaders;
|
|
964
|
+
}
|
|
965
|
+
prepareBody(body, bodyType) {
|
|
966
|
+
switch (bodyType) {
|
|
967
|
+
case HTTPBodyType.JSON:
|
|
968
|
+
return body;
|
|
969
|
+
case HTTPBodyType.FormData:
|
|
970
|
+
const formData = new FormData();
|
|
971
|
+
try {
|
|
972
|
+
const data = JSON.parse(body);
|
|
973
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
974
|
+
formData.append(key, String(value));
|
|
975
|
+
});
|
|
976
|
+
} catch (error) {
|
|
977
|
+
throw new Error("Invalid FormData body format");
|
|
978
|
+
}
|
|
979
|
+
return formData;
|
|
980
|
+
case HTTPBodyType.XWwwFormUrlencoded:
|
|
981
|
+
try {
|
|
982
|
+
const data = JSON.parse(body);
|
|
983
|
+
const params = new URLSearchParams();
|
|
984
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
985
|
+
params.append(key, String(value));
|
|
986
|
+
});
|
|
987
|
+
return params.toString();
|
|
988
|
+
} catch (error) {
|
|
989
|
+
throw new Error("Invalid x-www-form-urlencoded body format");
|
|
990
|
+
}
|
|
991
|
+
case HTTPBodyType.RawText:
|
|
992
|
+
case HTTPBodyType.Binary:
|
|
993
|
+
default:
|
|
994
|
+
return body;
|
|
796
995
|
}
|
|
797
996
|
}
|
|
798
997
|
};
|
|
@@ -832,6 +1031,19 @@ var BlockEndExecutor = class {
|
|
|
832
1031
|
}
|
|
833
1032
|
};
|
|
834
1033
|
|
|
1034
|
+
// src/nodes/continue/index.ts
|
|
1035
|
+
var ContinueExecutor = class {
|
|
1036
|
+
constructor() {
|
|
1037
|
+
this.type = FlowGramNode.Continue;
|
|
1038
|
+
}
|
|
1039
|
+
async execute(context) {
|
|
1040
|
+
context.runtime.cache.set("loop-continue", true);
|
|
1041
|
+
return {
|
|
1042
|
+
outputs: {}
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
|
|
835
1047
|
// src/nodes/condition/index.ts
|
|
836
1048
|
import { isNil as isNil9 } from "lodash-es";
|
|
837
1049
|
|
|
@@ -1123,7 +1335,7 @@ var ConditionExecutor = class {
|
|
|
1123
1335
|
`Condition left type "${condition.leftType}" has no operator "${condition.operator}"`
|
|
1124
1336
|
);
|
|
1125
1337
|
}
|
|
1126
|
-
if (ruleType
|
|
1338
|
+
if (!WorkflowRuntimeType.isTypeEqual(ruleType, condition.rightType)) {
|
|
1127
1339
|
return false;
|
|
1128
1340
|
}
|
|
1129
1341
|
return true;
|
|
@@ -1138,6 +1350,81 @@ var ConditionExecutor = class {
|
|
|
1138
1350
|
}
|
|
1139
1351
|
};
|
|
1140
1352
|
|
|
1353
|
+
// src/nodes/code/index.ts
|
|
1354
|
+
var CodeExecutor = class {
|
|
1355
|
+
constructor() {
|
|
1356
|
+
this.type = FlowGramNode.Code;
|
|
1357
|
+
}
|
|
1358
|
+
async execute(context) {
|
|
1359
|
+
const inputs = this.parseInputs(context);
|
|
1360
|
+
if (inputs.script.language === "javascript") {
|
|
1361
|
+
return this.javascript(inputs);
|
|
1362
|
+
}
|
|
1363
|
+
throw new Error(`Unsupported code language "${inputs.script.language}"`);
|
|
1364
|
+
}
|
|
1365
|
+
parseInputs(context) {
|
|
1366
|
+
const codeNode = context.node;
|
|
1367
|
+
const params = context.inputs;
|
|
1368
|
+
const { language, content } = codeNode.data.script;
|
|
1369
|
+
if (!content) {
|
|
1370
|
+
throw new Error("Code content is required");
|
|
1371
|
+
}
|
|
1372
|
+
return {
|
|
1373
|
+
params,
|
|
1374
|
+
script: {
|
|
1375
|
+
language,
|
|
1376
|
+
content
|
|
1377
|
+
}
|
|
1378
|
+
};
|
|
1379
|
+
}
|
|
1380
|
+
async javascript(inputs) {
|
|
1381
|
+
const { params = {}, script } = inputs;
|
|
1382
|
+
try {
|
|
1383
|
+
const executeCode = new Function(
|
|
1384
|
+
"params",
|
|
1385
|
+
`
|
|
1386
|
+
'use strict';
|
|
1387
|
+
|
|
1388
|
+
${script.content}
|
|
1389
|
+
|
|
1390
|
+
// Ensure main function exists
|
|
1391
|
+
if (typeof main !== 'function') {
|
|
1392
|
+
throw new Error('main function is required in the script');
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
// Execute main function with params
|
|
1396
|
+
return main({ params });
|
|
1397
|
+
`
|
|
1398
|
+
);
|
|
1399
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1400
|
+
setTimeout(() => {
|
|
1401
|
+
reject(new Error("Code execution timeout: exceeded 1 minute"));
|
|
1402
|
+
}, 1e3 * 60);
|
|
1403
|
+
});
|
|
1404
|
+
const result = await Promise.race([executeCode(params), timeoutPromise]);
|
|
1405
|
+
const outputs = result && typeof result === "object" && !Array.isArray(result) ? result : { result };
|
|
1406
|
+
return {
|
|
1407
|
+
outputs
|
|
1408
|
+
};
|
|
1409
|
+
} catch (error) {
|
|
1410
|
+
throw new Error(`Code execution failed: ${error.message}`);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
|
|
1415
|
+
// src/nodes/break/index.ts
|
|
1416
|
+
var BreakExecutor = class {
|
|
1417
|
+
constructor() {
|
|
1418
|
+
this.type = FlowGramNode.Break;
|
|
1419
|
+
}
|
|
1420
|
+
async execute(context) {
|
|
1421
|
+
context.runtime.cache.set("loop-break", true);
|
|
1422
|
+
return {
|
|
1423
|
+
outputs: {}
|
|
1424
|
+
};
|
|
1425
|
+
}
|
|
1426
|
+
};
|
|
1427
|
+
|
|
1141
1428
|
// src/nodes/index.ts
|
|
1142
1429
|
var WorkflowRuntimeNodeExecutors = [
|
|
1143
1430
|
StartExecutor,
|
|
@@ -1146,7 +1433,11 @@ var WorkflowRuntimeNodeExecutors = [
|
|
|
1146
1433
|
ConditionExecutor,
|
|
1147
1434
|
LoopExecutor,
|
|
1148
1435
|
BlockStartExecutor,
|
|
1149
|
-
BlockEndExecutor
|
|
1436
|
+
BlockEndExecutor,
|
|
1437
|
+
HTTPExecutor,
|
|
1438
|
+
CodeExecutor,
|
|
1439
|
+
BreakExecutor,
|
|
1440
|
+
ContinueExecutor
|
|
1150
1441
|
];
|
|
1151
1442
|
|
|
1152
1443
|
// src/domain/validation/validators/cycle-detection.ts
|
|
@@ -1565,6 +1856,29 @@ var WorkflowRuntimeMessageCenter = class {
|
|
|
1565
1856
|
}
|
|
1566
1857
|
};
|
|
1567
1858
|
|
|
1859
|
+
// src/domain/cache/index.ts
|
|
1860
|
+
var WorkflowRuntimeCache = class {
|
|
1861
|
+
init() {
|
|
1862
|
+
this.map = /* @__PURE__ */ new Map();
|
|
1863
|
+
}
|
|
1864
|
+
dispose() {
|
|
1865
|
+
this.map.clear();
|
|
1866
|
+
}
|
|
1867
|
+
get(key) {
|
|
1868
|
+
return this.map.get(key);
|
|
1869
|
+
}
|
|
1870
|
+
set(key, value) {
|
|
1871
|
+
this.map.set(key, value);
|
|
1872
|
+
return this;
|
|
1873
|
+
}
|
|
1874
|
+
delete(key) {
|
|
1875
|
+
return this.map.delete(key);
|
|
1876
|
+
}
|
|
1877
|
+
has(key) {
|
|
1878
|
+
return this.map.has(key);
|
|
1879
|
+
}
|
|
1880
|
+
};
|
|
1881
|
+
|
|
1568
1882
|
// src/domain/variable/variable-store/index.ts
|
|
1569
1883
|
import { get, set } from "lodash-es";
|
|
1570
1884
|
|
|
@@ -1790,26 +2104,10 @@ var WorkflowRuntimeState = class {
|
|
|
1790
2104
|
getNodeInputs(node) {
|
|
1791
2105
|
const inputsDeclare = node.declare.inputs;
|
|
1792
2106
|
const inputsValues = node.declare.inputsValues;
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
const typeInfo = inputsDeclare.properties?.[key];
|
|
1798
|
-
if (!typeInfo) {
|
|
1799
|
-
return prev;
|
|
1800
|
-
}
|
|
1801
|
-
const expectType = typeInfo.type;
|
|
1802
|
-
const result = this.parseValue(inputValue);
|
|
1803
|
-
if (!result) {
|
|
1804
|
-
return prev;
|
|
1805
|
-
}
|
|
1806
|
-
const { value, type } = result;
|
|
1807
|
-
if (!WorkflowRuntimeType.isTypeEqual(type, expectType)) {
|
|
1808
|
-
return prev;
|
|
1809
|
-
}
|
|
1810
|
-
prev[key] = value;
|
|
1811
|
-
return prev;
|
|
1812
|
-
}, {});
|
|
2107
|
+
return this.parseInputs({
|
|
2108
|
+
values: inputsValues,
|
|
2109
|
+
declare: inputsDeclare
|
|
2110
|
+
});
|
|
1813
2111
|
}
|
|
1814
2112
|
setNodeOutputs(params) {
|
|
1815
2113
|
const { node, outputs } = params;
|
|
@@ -1833,6 +2131,29 @@ var WorkflowRuntimeState = class {
|
|
|
1833
2131
|
});
|
|
1834
2132
|
});
|
|
1835
2133
|
}
|
|
2134
|
+
parseInputs(params) {
|
|
2135
|
+
const { values, declare } = params;
|
|
2136
|
+
if (!declare || !values) {
|
|
2137
|
+
return {};
|
|
2138
|
+
}
|
|
2139
|
+
return Object.entries(values).reduce((prev, [key, inputValue]) => {
|
|
2140
|
+
const typeInfo = declare.properties?.[key];
|
|
2141
|
+
if (!typeInfo) {
|
|
2142
|
+
return prev;
|
|
2143
|
+
}
|
|
2144
|
+
const expectType = typeInfo.type;
|
|
2145
|
+
const result = this.parseValue(inputValue);
|
|
2146
|
+
if (!result) {
|
|
2147
|
+
return prev;
|
|
2148
|
+
}
|
|
2149
|
+
const { value, type } = result;
|
|
2150
|
+
if (!WorkflowRuntimeType.isTypeEqual(type, expectType)) {
|
|
2151
|
+
return prev;
|
|
2152
|
+
}
|
|
2153
|
+
prev[key] = value;
|
|
2154
|
+
return prev;
|
|
2155
|
+
}, {});
|
|
2156
|
+
}
|
|
1836
2157
|
parseRef(ref) {
|
|
1837
2158
|
if (ref?.type !== "ref") {
|
|
1838
2159
|
throw new Error(`Invalid ref value: ${ref}`);
|
|
@@ -2366,6 +2687,7 @@ var WorkflowRuntimeContext = class _WorkflowRuntimeContext {
|
|
|
2366
2687
|
constructor(data) {
|
|
2367
2688
|
this.subContexts = [];
|
|
2368
2689
|
this.id = uuid();
|
|
2690
|
+
this.cache = data.cache;
|
|
2369
2691
|
this.document = data.document;
|
|
2370
2692
|
this.variableStore = data.variableStore;
|
|
2371
2693
|
this.state = data.state;
|
|
@@ -2377,6 +2699,7 @@ var WorkflowRuntimeContext = class _WorkflowRuntimeContext {
|
|
|
2377
2699
|
}
|
|
2378
2700
|
init(params) {
|
|
2379
2701
|
const { schema, inputs } = params;
|
|
2702
|
+
this.cache.init();
|
|
2380
2703
|
this.document.init(schema);
|
|
2381
2704
|
this.variableStore.init();
|
|
2382
2705
|
this.state.init();
|
|
@@ -2391,6 +2714,7 @@ var WorkflowRuntimeContext = class _WorkflowRuntimeContext {
|
|
|
2391
2714
|
subContext.dispose();
|
|
2392
2715
|
});
|
|
2393
2716
|
this.subContexts = [];
|
|
2717
|
+
this.cache.dispose();
|
|
2394
2718
|
this.document.dispose();
|
|
2395
2719
|
this.variableStore.dispose();
|
|
2396
2720
|
this.state.dispose();
|
|
@@ -2401,10 +2725,12 @@ var WorkflowRuntimeContext = class _WorkflowRuntimeContext {
|
|
|
2401
2725
|
this.reporter.dispose();
|
|
2402
2726
|
}
|
|
2403
2727
|
sub() {
|
|
2728
|
+
const cache = new WorkflowRuntimeCache();
|
|
2404
2729
|
const variableStore = new WorkflowRuntimeVariableStore();
|
|
2405
2730
|
variableStore.setParent(this.variableStore);
|
|
2406
2731
|
const state = new WorkflowRuntimeState(variableStore);
|
|
2407
2732
|
const contextData = {
|
|
2733
|
+
cache,
|
|
2408
2734
|
document: this.document,
|
|
2409
2735
|
ioCenter: this.ioCenter,
|
|
2410
2736
|
snapshotCenter: this.snapshotCenter,
|
|
@@ -2416,11 +2742,13 @@ var WorkflowRuntimeContext = class _WorkflowRuntimeContext {
|
|
|
2416
2742
|
};
|
|
2417
2743
|
const subContext = new _WorkflowRuntimeContext(contextData);
|
|
2418
2744
|
this.subContexts.push(subContext);
|
|
2745
|
+
subContext.cache.init();
|
|
2419
2746
|
subContext.variableStore.init();
|
|
2420
2747
|
subContext.state.init();
|
|
2421
2748
|
return subContext;
|
|
2422
2749
|
}
|
|
2423
2750
|
static create() {
|
|
2751
|
+
const cache = new WorkflowRuntimeCache();
|
|
2424
2752
|
const document = new WorkflowRuntimeDocument();
|
|
2425
2753
|
const variableStore = new WorkflowRuntimeVariableStore();
|
|
2426
2754
|
const state = new WorkflowRuntimeState(variableStore);
|
|
@@ -2435,6 +2763,7 @@ var WorkflowRuntimeContext = class _WorkflowRuntimeContext {
|
|
|
2435
2763
|
messageCenter
|
|
2436
2764
|
);
|
|
2437
2765
|
return new _WorkflowRuntimeContext({
|
|
2766
|
+
cache,
|
|
2438
2767
|
document,
|
|
2439
2768
|
variableStore,
|
|
2440
2769
|
state,
|
|
@@ -2492,7 +2821,8 @@ var WorkflowRuntimeEngine = class {
|
|
|
2492
2821
|
node,
|
|
2493
2822
|
inputs,
|
|
2494
2823
|
runtime: context,
|
|
2495
|
-
container: WorkflowRuntimeContainer.instance
|
|
2824
|
+
container: WorkflowRuntimeContainer.instance,
|
|
2825
|
+
snapshot
|
|
2496
2826
|
});
|
|
2497
2827
|
if (context.statusCenter.workflow.terminated) {
|
|
2498
2828
|
return;
|
|
@@ -2573,7 +2903,13 @@ var WorkflowRuntimeEngine = class {
|
|
|
2573
2903
|
}
|
|
2574
2904
|
async executeNext(params) {
|
|
2575
2905
|
const { context, node, nextNodes } = params;
|
|
2576
|
-
|
|
2906
|
+
const terminatingNodeTypes = [
|
|
2907
|
+
FlowGramNode.End,
|
|
2908
|
+
FlowGramNode.BlockEnd,
|
|
2909
|
+
FlowGramNode.Break,
|
|
2910
|
+
FlowGramNode.Continue
|
|
2911
|
+
];
|
|
2912
|
+
if (terminatingNodeTypes.includes(node.type)) {
|
|
2577
2913
|
return;
|
|
2578
2914
|
}
|
|
2579
2915
|
if (nextNodes.length === 0) {
|