@foresthubai/workflow-core 0.3.0 → 0.4.0

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.
Files changed (77) hide show
  1. package/LICENSE +202 -202
  2. package/NOTICE +14 -14
  3. package/README.md +63 -63
  4. package/dist/api/workflow.d.ts +2 -2
  5. package/dist/api/workflow.d.ts.map +1 -1
  6. package/package.json +1 -1
  7. package/src/api/index.ts +11 -11
  8. package/src/api/workflow.ts +607 -607
  9. package/src/channel/Channel.ts +11 -11
  10. package/src/channel/ChannelDefinition.ts +76 -76
  11. package/src/channel/index.ts +6 -6
  12. package/src/channel/serialization.ts +68 -68
  13. package/src/deploy/index.ts +1 -1
  14. package/src/deploy/requirements.test.ts +61 -61
  15. package/src/deploy/requirements.ts +41 -41
  16. package/src/diagnostics/__fixtures__/diagnosticFixtures.ts +158 -158
  17. package/src/diagnostics/diagnostics.test.ts +878 -878
  18. package/src/diagnostics/diagnostics.ts +936 -936
  19. package/src/diagnostics/index.ts +11 -11
  20. package/src/edge/Edge.ts +23 -23
  21. package/src/edge/EdgeDefinition.ts +45 -45
  22. package/src/edge/EdgeType.ts +19 -19
  23. package/src/edge/index.ts +8 -8
  24. package/src/edge/serialization.ts +83 -83
  25. package/src/expression/index.ts +4 -4
  26. package/src/expression/parser.ts +362 -362
  27. package/src/expression/types.ts +30 -30
  28. package/src/function/FunctionDeclaration.ts +54 -54
  29. package/src/function/index.ts +3 -3
  30. package/src/function/serialization.ts +40 -40
  31. package/src/globals.d.ts +9 -9
  32. package/src/id/index.ts +8 -8
  33. package/src/index.ts +22 -22
  34. package/src/memory/Memory.ts +15 -15
  35. package/src/memory/MemoryDefinition.ts +16 -16
  36. package/src/memory/MemoryFileDefinition.ts +37 -37
  37. package/src/memory/MemoryRegistry.ts +35 -35
  38. package/src/memory/VectorDatabaseDefinition.ts +21 -21
  39. package/src/memory/index.ts +8 -8
  40. package/src/memory/serialization.ts +47 -47
  41. package/src/migration/index.ts +4 -4
  42. package/src/migration/migrate.test.ts +44 -44
  43. package/src/migration/migrate.ts +58 -58
  44. package/src/migration/migrations.ts +24 -24
  45. package/src/migration/version.ts +9 -9
  46. package/src/model/LLMModelDefinition.ts +12 -12
  47. package/src/model/Model.ts +39 -39
  48. package/src/model/ModelDefinition.ts +15 -15
  49. package/src/model/ModelRegistry.ts +33 -33
  50. package/src/model/index.ts +7 -7
  51. package/src/model/serialization.ts +30 -30
  52. package/src/node/AgentNode.ts +82 -82
  53. package/src/node/DataNode.ts +41 -41
  54. package/src/node/FunctionNode.ts +76 -76
  55. package/src/node/InputNode.ts +185 -185
  56. package/src/node/LogicNode.ts +33 -33
  57. package/src/node/MqttNode.ts +127 -127
  58. package/src/node/Node.ts +61 -61
  59. package/src/node/NodeDefinition.ts +37 -37
  60. package/src/node/NodeRegistry.ts +85 -85
  61. package/src/node/OutputNode.ts +87 -87
  62. package/src/node/ToolNode.ts +32 -32
  63. package/src/node/TriggerNode.ts +272 -272
  64. package/src/node/constants.ts +16 -16
  65. package/src/node/index.ts +26 -26
  66. package/src/node/methods.ts +278 -278
  67. package/src/node/serialization.ts +544 -544
  68. package/src/parameter/OutputParameter.ts +68 -68
  69. package/src/parameter/Parameter.ts +243 -243
  70. package/src/parameter/index.ts +33 -33
  71. package/src/variable/Variable.ts +10 -10
  72. package/src/variable/index.ts +16 -16
  73. package/src/variable/operations.ts +106 -106
  74. package/src/workflow/Workflow.ts +41 -41
  75. package/src/workflow/index.ts +3 -3
  76. package/src/workflow/serialization.test.ts +240 -240
  77. package/src/workflow/serialization.ts +242 -242
@@ -1,30 +1,30 @@
1
- import type { Schemas } from "../api";
2
- import type { Model, ModelCapability } from "./Model";
3
-
4
- export type ApiModel = Schemas["Model"];
5
-
6
- /** Serialize a domain Model to the API discriminated-union shape. */
7
- export function serialize(model: Model): ApiModel {
8
- const { id, label, type, arguments: args } = model;
9
- switch (type) {
10
- case "LLMModel":
11
- return {
12
- type,
13
- id,
14
- label,
15
- capabilities: (args.capabilities as ModelCapability[]) ?? ["chat"],
16
- };
17
- }
18
- }
19
-
20
- /** Convert an API Model into a domain Model. */
21
- export function deserialize(api: ApiModel): Model {
22
- const { id, label, type } = api;
23
- const args: Record<string, unknown> = {};
24
- switch (type) {
25
- case "LLMModel":
26
- args.capabilities = api.capabilities;
27
- break;
28
- }
29
- return { id, label, type, arguments: args };
30
- }
1
+ import type { Schemas } from "../api";
2
+ import type { Model, ModelCapability } from "./Model";
3
+
4
+ export type ApiModel = Schemas["Model"];
5
+
6
+ /** Serialize a domain Model to the API discriminated-union shape. */
7
+ export function serialize(model: Model): ApiModel {
8
+ const { id, label, type, arguments: args } = model;
9
+ switch (type) {
10
+ case "LLMModel":
11
+ return {
12
+ type,
13
+ id,
14
+ label,
15
+ capabilities: (args.capabilities as ModelCapability[]) ?? ["chat"],
16
+ };
17
+ }
18
+ }
19
+
20
+ /** Convert an API Model into a domain Model. */
21
+ export function deserialize(api: ApiModel): Model {
22
+ const { id, label, type } = api;
23
+ const args: Record<string, unknown> = {};
24
+ switch (type) {
25
+ case "LLMModel":
26
+ args.capabilities = api.capabilities;
27
+ break;
28
+ }
29
+ return { id, label, type, arguments: args };
30
+ }
@@ -1,82 +1,82 @@
1
- import { NodeBase } from "./Node";
2
- import { OutputBinding, OutputDeclaration } from "../parameter";
3
- import type { Schemas } from "../api";
4
- import { NodeCategory } from "./constants";
5
- import { NodeDefinition } from "./NodeDefinition";
6
-
7
- export type MemoryRef = Schemas["MemoryRef"];
8
-
9
- export interface AgentNode extends NodeBase {
10
- type: "Agent";
11
- arguments: {
12
- name: string;
13
- model: string;
14
- instructions: string;
15
- maxTurns: number | undefined;
16
- outputDeclarations: OutputDeclaration[];
17
- memoryRefs: MemoryRef[];
18
- answer: OutputBinding;
19
- toolDescription?: string;
20
- };
21
- }
22
-
23
- export type AgentNodeType = "Agent";
24
-
25
- export const AgentNodeDefinition: NodeDefinition = {
26
- type: "Agent",
27
- label: "LLM Agent",
28
- category: NodeCategory.AI,
29
- description: "AI-powered agent for intelligent processing",
30
- canBranch: true, // Control output may fan out to multiple branches (tool output is always multi-target).
31
- outputs: [
32
- { id: "answer", label: "Answer", type: "static", dataType: "string" },
33
- { id: "outputDeclarations", label: "Structured Output", type: "list" },
34
- ],
35
- parameters: [
36
- {
37
- id: "name",
38
- label: "Name",
39
- description: "Name of the agent",
40
- optional: true,
41
- type: "string",
42
- },
43
- {
44
- id: "model",
45
- label: "Model",
46
- description: "AI model to use for the agent",
47
- type: "modelSelect",
48
- modelType: ["LLMModel"],
49
- capabilities: ["chat"],
50
- },
51
- {
52
- id: "instructions",
53
- label: "Instructions",
54
- description: "Instructions for the cloud agent that act as system prompt",
55
- type: "string",
56
- multiline: true,
57
- optional: true,
58
- },
59
- {
60
- id: "maxTurns",
61
- label: "Max Turns",
62
- description: "Maximum number of agent runner turns",
63
- type: "int",
64
- optional: true,
65
- },
66
- {
67
- id: "memoryRefs",
68
- label: "Memory Files",
69
- description: "Project memory files this agent can access, with per-file read or read+write mode",
70
- type: "memory-refs",
71
- default: [],
72
- },
73
- {
74
- id: "toolDescription",
75
- label: "Tool Description",
76
- description: "Description shown to the calling agent when this agent is wired as a tool",
77
- type: "string",
78
- multiline: true,
79
- activationRules: [{ type: "isToolInput" }],
80
- },
81
- ],
82
- };
1
+ import { NodeBase } from "./Node";
2
+ import { OutputBinding, OutputDeclaration } from "../parameter";
3
+ import type { Schemas } from "../api";
4
+ import { NodeCategory } from "./constants";
5
+ import { NodeDefinition } from "./NodeDefinition";
6
+
7
+ export type MemoryRef = Schemas["MemoryRef"];
8
+
9
+ export interface AgentNode extends NodeBase {
10
+ type: "Agent";
11
+ arguments: {
12
+ name: string;
13
+ model: string;
14
+ instructions: string;
15
+ maxTurns: number | undefined;
16
+ outputDeclarations: OutputDeclaration[];
17
+ memoryRefs: MemoryRef[];
18
+ answer: OutputBinding;
19
+ toolDescription?: string;
20
+ };
21
+ }
22
+
23
+ export type AgentNodeType = "Agent";
24
+
25
+ export const AgentNodeDefinition: NodeDefinition = {
26
+ type: "Agent",
27
+ label: "LLM Agent",
28
+ category: NodeCategory.AI,
29
+ description: "AI-powered agent for intelligent processing",
30
+ canBranch: true, // Control output may fan out to multiple branches (tool output is always multi-target).
31
+ outputs: [
32
+ { id: "answer", label: "Answer", type: "static", dataType: "string" },
33
+ { id: "outputDeclarations", label: "Structured Output", type: "list" },
34
+ ],
35
+ parameters: [
36
+ {
37
+ id: "name",
38
+ label: "Name",
39
+ description: "Name of the agent",
40
+ optional: true,
41
+ type: "string",
42
+ },
43
+ {
44
+ id: "model",
45
+ label: "Model",
46
+ description: "AI model to use for the agent",
47
+ type: "modelSelect",
48
+ modelType: ["LLMModel"],
49
+ capabilities: ["chat"],
50
+ },
51
+ {
52
+ id: "instructions",
53
+ label: "Instructions",
54
+ description: "Instructions for the cloud agent that act as system prompt",
55
+ type: "string",
56
+ multiline: true,
57
+ optional: true,
58
+ },
59
+ {
60
+ id: "maxTurns",
61
+ label: "Max Turns",
62
+ description: "Maximum number of agent runner turns",
63
+ type: "int",
64
+ optional: true,
65
+ },
66
+ {
67
+ id: "memoryRefs",
68
+ label: "Memory Files",
69
+ description: "Project memory files this agent can access, with per-file read or read+write mode",
70
+ type: "memory-refs",
71
+ default: [],
72
+ },
73
+ {
74
+ id: "toolDescription",
75
+ label: "Tool Description",
76
+ description: "Description shown to the calling agent when this agent is wired as a tool",
77
+ type: "string",
78
+ multiline: true,
79
+ activationRules: [{ type: "isToolInput" }],
80
+ },
81
+ ],
82
+ };
@@ -1,41 +1,41 @@
1
- import { NodeBase } from "./Node";
2
- import type { Expression, Reference } from "../api";
3
- import { NodeCategory } from "./constants";
4
- import { NodeDefinition } from "./NodeDefinition";
5
-
6
- export interface SetVariableNode extends NodeBase {
7
- type: "SetVariable";
8
- arguments: {
9
- variable: Reference | undefined;
10
- value: Expression;
11
- };
12
- }
13
-
14
- export type DataNodeType = "SetVariable";
15
- export type DataNode = SetVariableNode;
16
-
17
- // Node Definitions
18
-
19
- export const SetVariableNodeDefinition: NodeDefinition = {
20
- type: "SetVariable",
21
- label: "Set Variable",
22
- category: NodeCategory.Data,
23
- description: "Assign a new value to an existing variable",
24
- parameters: [
25
- {
26
- id: "variable",
27
- label: "Variable",
28
- description: "The variable to update",
29
- type: "variableSelect",
30
- },
31
- {
32
- id: "value",
33
- label: "Value",
34
- description: "Expression to assign",
35
- type: "expression",
36
- expressionType: "int", // fallback; actual type is derived from the target variable (see fromReference)
37
- fromReference: "variable",
38
- default: { expression: "", references: [], dataType: "int" },
39
- },
40
- ],
41
- };
1
+ import { NodeBase } from "./Node";
2
+ import type { Expression, Reference } from "../api";
3
+ import { NodeCategory } from "./constants";
4
+ import { NodeDefinition } from "./NodeDefinition";
5
+
6
+ export interface SetVariableNode extends NodeBase {
7
+ type: "SetVariable";
8
+ arguments: {
9
+ variable: Reference | undefined;
10
+ value: Expression;
11
+ };
12
+ }
13
+
14
+ export type DataNodeType = "SetVariable";
15
+ export type DataNode = SetVariableNode;
16
+
17
+ // Node Definitions
18
+
19
+ export const SetVariableNodeDefinition: NodeDefinition = {
20
+ type: "SetVariable",
21
+ label: "Set Variable",
22
+ category: NodeCategory.Data,
23
+ description: "Assign a new value to an existing variable",
24
+ parameters: [
25
+ {
26
+ id: "variable",
27
+ label: "Variable",
28
+ description: "The variable to update",
29
+ type: "variableSelect",
30
+ },
31
+ {
32
+ id: "value",
33
+ label: "Value",
34
+ description: "Expression to assign",
35
+ type: "expression",
36
+ expressionType: "int", // fallback; actual type is derived from the target variable (see fromReference)
37
+ fromReference: "variable",
38
+ default: { expression: "", references: [], dataType: "int" },
39
+ },
40
+ ],
41
+ };
@@ -1,76 +1,76 @@
1
- import { NodeBase } from "./Node";
2
- import type { Expression } from "../api";
3
- import type { FunctionInfo } from "../function";
4
- import type { DataType } from "../api";
5
- import { OutputBinding } from "../parameter";
6
- import { NodeDefinition } from "./NodeDefinition";
7
- import { NodeCategory } from "./constants";
8
- import { paramKey } from "../variable";
9
-
10
- // Function Call Node - invokes a user-defined function.
11
- // Arguments are flat — keyed by Variable uid. Input argument uids map to Expression,
12
- // return uids map to OutputBinding. Same shape as every other node, so the rest of
13
- // the system (parameter editors, output bindings, merge/update) treats FunctionCall
14
- // uniformly. Outputs are derived on-the-fly via buildFunctionNodeDef from
15
- // functionInfo.returns — there is no registered NodeDefinition.
16
- export interface FunctionCallNode extends NodeBase {
17
- type: "FunctionCall";
18
- functionInfo: FunctionInfo; // Snapshot at creation; may be stale vs registry
19
- // Flat bag keyed by Variable uid (Expression for args, OutputBinding for returns),
20
- // plus the reserved `toolDescription` key (string) for the tool-mode parameter.
21
- arguments: Record<string, Expression | OutputBinding | string>;
22
- }
23
-
24
- export type FunctionCallNodeType = "FunctionCall";
25
-
26
- // FunctionNodeDefinition extends NodeDefinition with function-specific fields
27
- // Used by NodeLibrary to create new FunctionCall nodes
28
- export interface FunctionNodeDefinition extends NodeDefinition {
29
- type: "FunctionCall";
30
- functionInfo: FunctionInfo; // Metadata about the function being called
31
- }
32
-
33
- /**
34
- * Build a FunctionCall NodeDefinition from FunctionInfo. Pure — takes an
35
- * optional translator function so the headless validator can call it without
36
- * an i18n runtime; workflow-builder passes `i18n.t.bind(i18n)` to get
37
- * translated descriptions. Defaults to identity (returns the key) when no
38
- * translator is supplied; validation logic ignores description strings.
39
- */
40
- export function buildFunctionNodeDef(
41
- fn: FunctionInfo,
42
- t: (key: string, params?: Record<string, unknown>) => string = (key) => key,
43
- ): FunctionNodeDefinition {
44
- return {
45
- type: "FunctionCall",
46
- functionInfo: fn,
47
- label: fn.name,
48
- category: NodeCategory.Function,
49
- description: t("builder.functionCallDesc", { name: fn.name }),
50
- parameters: [
51
- ...fn.arguments.map((param) => ({
52
- id: paramKey(param),
53
- label: param.name,
54
- description: t("builder.functionParamDesc", { name: param.name }),
55
- type: "expression" as const,
56
- expressionType: param.dataType as DataType,
57
- default: { expression: "", references: [], dataType: param.dataType as DataType },
58
- activationRules: [{ type: "isControlFlow" as const }],
59
- })),
60
- {
61
- id: "toolDescription",
62
- label: "Tool Description",
63
- description: "Description shown to the agent when this function is wired as a tool",
64
- type: "string" as const,
65
- multiline: true,
66
- activationRules: [{ type: "isToolInput" as const }],
67
- },
68
- ],
69
- outputs: fn.returns.map((ret) => ({
70
- id: paramKey(ret),
71
- label: ret.name,
72
- type: "static" as const,
73
- dataType: ret.dataType as DataType,
74
- })),
75
- };
76
- }
1
+ import { NodeBase } from "./Node";
2
+ import type { Expression } from "../api";
3
+ import type { FunctionInfo } from "../function";
4
+ import type { DataType } from "../api";
5
+ import { OutputBinding } from "../parameter";
6
+ import { NodeDefinition } from "./NodeDefinition";
7
+ import { NodeCategory } from "./constants";
8
+ import { paramKey } from "../variable";
9
+
10
+ // Function Call Node - invokes a user-defined function.
11
+ // Arguments are flat — keyed by Variable uid. Input argument uids map to Expression,
12
+ // return uids map to OutputBinding. Same shape as every other node, so the rest of
13
+ // the system (parameter editors, output bindings, merge/update) treats FunctionCall
14
+ // uniformly. Outputs are derived on-the-fly via buildFunctionNodeDef from
15
+ // functionInfo.returns — there is no registered NodeDefinition.
16
+ export interface FunctionCallNode extends NodeBase {
17
+ type: "FunctionCall";
18
+ functionInfo: FunctionInfo; // Snapshot at creation; may be stale vs registry
19
+ // Flat bag keyed by Variable uid (Expression for args, OutputBinding for returns),
20
+ // plus the reserved `toolDescription` key (string) for the tool-mode parameter.
21
+ arguments: Record<string, Expression | OutputBinding | string>;
22
+ }
23
+
24
+ export type FunctionCallNodeType = "FunctionCall";
25
+
26
+ // FunctionNodeDefinition extends NodeDefinition with function-specific fields
27
+ // Used by NodeLibrary to create new FunctionCall nodes
28
+ export interface FunctionNodeDefinition extends NodeDefinition {
29
+ type: "FunctionCall";
30
+ functionInfo: FunctionInfo; // Metadata about the function being called
31
+ }
32
+
33
+ /**
34
+ * Build a FunctionCall NodeDefinition from FunctionInfo. Pure — takes an
35
+ * optional translator function so the headless validator can call it without
36
+ * an i18n runtime; workflow-builder passes `i18n.t.bind(i18n)` to get
37
+ * translated descriptions. Defaults to identity (returns the key) when no
38
+ * translator is supplied; validation logic ignores description strings.
39
+ */
40
+ export function buildFunctionNodeDef(
41
+ fn: FunctionInfo,
42
+ t: (key: string, params?: Record<string, unknown>) => string = (key) => key,
43
+ ): FunctionNodeDefinition {
44
+ return {
45
+ type: "FunctionCall",
46
+ functionInfo: fn,
47
+ label: fn.name,
48
+ category: NodeCategory.Function,
49
+ description: t("builder.functionCallDesc", { name: fn.name }),
50
+ parameters: [
51
+ ...fn.arguments.map((param) => ({
52
+ id: paramKey(param),
53
+ label: param.name,
54
+ description: t("builder.functionParamDesc", { name: param.name }),
55
+ type: "expression" as const,
56
+ expressionType: param.dataType as DataType,
57
+ default: { expression: "", references: [], dataType: param.dataType as DataType },
58
+ activationRules: [{ type: "isControlFlow" as const }],
59
+ })),
60
+ {
61
+ id: "toolDescription",
62
+ label: "Tool Description",
63
+ description: "Description shown to the agent when this function is wired as a tool",
64
+ type: "string" as const,
65
+ multiline: true,
66
+ activationRules: [{ type: "isToolInput" as const }],
67
+ },
68
+ ],
69
+ outputs: fn.returns.map((ret) => ({
70
+ id: paramKey(ret),
71
+ label: ret.name,
72
+ type: "static" as const,
73
+ dataType: ret.dataType as DataType,
74
+ })),
75
+ };
76
+ }