@lupaflow/workflow 0.1.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.
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@lupaflow/workflow",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "module": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "require": "./dist/index.js",
16
+ "import": "./dist/index.js"
17
+ }
18
+ },
19
+ "scripts": {
20
+ "build": "tsup",
21
+ "dev": "tsup --watch"
22
+ },
23
+ "dependencies": {
24
+ "@lupaflow/core": "workspace:*",
25
+ "@lupaflow/types": "workspace:*",
26
+ "@lupaflow/agent": "workspace:*"
27
+ },
28
+ "devDependencies": {
29
+ "tsup": "^8.3.0",
30
+ "typescript": "^5.6.0"
31
+ }
32
+ }
package/src/engine.ts ADDED
@@ -0,0 +1,100 @@
1
+ import type { WorkflowConfig, WorkflowResult } from "@lupaflow/types"
2
+ import { WorkflowStep } from "./step"
3
+ import { Pipeline } from "./pipeline"
4
+ import { generateId } from "@lupaflow/core"
5
+ import { globalEventBus } from "@lupaflow/core"
6
+ import { WorkflowError } from "@lupaflow/core"
7
+
8
+ export class WorkflowEngine {
9
+ public config: WorkflowConfig
10
+ public results: WorkflowResult[] = []
11
+
12
+ constructor(config: WorkflowConfig) {
13
+ this.config = { ...config, id: config.id || generateId() }
14
+ }
15
+
16
+ static fromPipeline(name: string, pipeline: Pipeline, description?: string): WorkflowEngine {
17
+ return new WorkflowEngine({
18
+ name,
19
+ description,
20
+ steps: pipeline.getSteps(),
21
+ })
22
+ }
23
+
24
+ async run(initialInput?: unknown): Promise<WorkflowResult> {
25
+ const start = Date.now()
26
+ const stepResults = []
27
+
28
+ await globalEventBus.emit("workflow:start", {
29
+ steps: this.config.steps.length,
30
+ } as any)
31
+
32
+ let currentInput = initialInput
33
+
34
+ for (let i = 0; i < this.config.steps.length; i++) {
35
+ const stepConfig = this.config.steps[i]
36
+ const step = new WorkflowStep(stepConfig)
37
+
38
+ await globalEventBus.emit("workflow:step", {
39
+ step: i + 1,
40
+ stepName: stepConfig.name,
41
+ status: "running",
42
+ } as any)
43
+
44
+ const stepResult = await step.execute(currentInput)
45
+ stepResults.push(stepResult)
46
+
47
+ await globalEventBus.emit("workflow:step", {
48
+ step: i + 1,
49
+ stepName: stepConfig.name,
50
+ status: stepResult.status === "success" ? "completed" : "failed",
51
+ } as any)
52
+
53
+ if (stepResult.status === "failed") {
54
+ if (this.config.maxRetries && i < this.config.steps.length - 1) {
55
+ stepResult.status = "success"
56
+ } else {
57
+ const result: WorkflowResult = {
58
+ id: this.config.id!,
59
+ name: this.config.name,
60
+ success: false,
61
+ steps: stepResults,
62
+ durationMs: Date.now() - start,
63
+ error: stepResult.error,
64
+ }
65
+
66
+ await globalEventBus.emit("workflow:complete", {
67
+ totalSteps: this.config.steps.length,
68
+ failedSteps: stepResults.filter((s) => s.status === "failed").length,
69
+ durationMs: result.durationMs,
70
+ } as any)
71
+
72
+ this.config.onError?.(new WorkflowError(stepResult.error!, stepConfig.id))
73
+ this.results.push(result)
74
+ return result
75
+ }
76
+ }
77
+
78
+ currentInput = stepResult.output
79
+ }
80
+
81
+ const durationMs = Date.now() - start
82
+ const result: WorkflowResult = {
83
+ id: this.config.id!,
84
+ name: this.config.name,
85
+ success: true,
86
+ steps: stepResults,
87
+ durationMs,
88
+ }
89
+
90
+ await globalEventBus.emit("workflow:complete", {
91
+ totalSteps: this.config.steps.length,
92
+ failedSteps: 0,
93
+ durationMs,
94
+ } as any)
95
+
96
+ this.config.onComplete?.(stepResults.map((s) => s.output))
97
+ this.results.push(result)
98
+ return result
99
+ }
100
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { WorkflowEngine } from "./engine"
2
+ export { WorkflowStep } from "./step"
3
+ export { Pipeline } from "./pipeline"
@@ -0,0 +1,49 @@
1
+ import type { WorkflowStepConfig } from "@lupaflow/types"
2
+
3
+ export class Pipeline {
4
+ public steps: WorkflowStepConfig[] = []
5
+
6
+ addAgent(name: string, config: Partial<WorkflowStepConfig>): this {
7
+ this.steps.push({
8
+ id: `step-${this.steps.length + 1}`,
9
+ name,
10
+ type: "agent",
11
+ ...config,
12
+ })
13
+ return this
14
+ }
15
+
16
+ addTool(name: string, config: Partial<WorkflowStepConfig>): this {
17
+ this.steps.push({
18
+ id: `step-${this.steps.length + 1}`,
19
+ name,
20
+ type: "tool",
21
+ ...config,
22
+ })
23
+ return this
24
+ }
25
+
26
+ addTransform(name: string, transform: (input: unknown) => unknown): this {
27
+ this.steps.push({
28
+ id: `step-${this.steps.length + 1}`,
29
+ name,
30
+ type: "transform",
31
+ transform,
32
+ })
33
+ return this
34
+ }
35
+
36
+ addCondition(name: string, condition: (input: unknown) => boolean): this {
37
+ this.steps.push({
38
+ id: `step-${this.steps.length + 1}`,
39
+ name,
40
+ type: "condition",
41
+ condition,
42
+ })
43
+ return this
44
+ }
45
+
46
+ getSteps(): WorkflowStepConfig[] {
47
+ return [...this.steps]
48
+ }
49
+ }
package/src/step.ts ADDED
@@ -0,0 +1,77 @@
1
+ import type { WorkflowStepConfig, WorkflowStepResult } from "@lupaflow/types"
2
+ import { Agent } from "@lupaflow/agent"
3
+ import { generateId } from "@lupaflow/core"
4
+
5
+ export class WorkflowStep {
6
+ public config: WorkflowStepConfig
7
+ public result?: WorkflowStepResult
8
+
9
+ constructor(config: WorkflowStepConfig) {
10
+ this.config = { ...config, id: config.id || generateId() }
11
+ }
12
+
13
+ async execute(input?: unknown): Promise<WorkflowStepResult> {
14
+ const start = Date.now()
15
+
16
+ try {
17
+ let output: unknown
18
+
19
+ switch (this.config.type) {
20
+ case "agent": {
21
+ if (!this.config.agent) throw new Error("Agent config required for agent step")
22
+ const agent = new Agent(this.config.agent)
23
+ const agentInput = this.config.input || input
24
+ const result = await agent.run(typeof agentInput === "string" ? agentInput : JSON.stringify(agentInput))
25
+ output = result.output
26
+ break
27
+ }
28
+ case "tool": {
29
+ if (!this.config.tool) throw new Error("Tool required for tool step")
30
+ const toolInput = this.config.input || input
31
+ output = await this.config.tool.execute(toolInput as Record<string, unknown>)
32
+ break
33
+ }
34
+ case "transform": {
35
+ if (!this.config.transform) throw new Error("Transform function required for transform step")
36
+ output = this.config.transform(input)
37
+ break
38
+ }
39
+ case "condition": {
40
+ if (!this.config.condition) throw new Error("Condition function required for condition step")
41
+ output = this.config.condition(input)
42
+ break
43
+ }
44
+ default: {
45
+ output = input
46
+ }
47
+ }
48
+
49
+ const durationMs = Date.now() - start
50
+ this.result = {
51
+ id: this.config.id,
52
+ name: this.config.name,
53
+ type: this.config.type,
54
+ status: "success",
55
+ input,
56
+ output,
57
+ durationMs,
58
+ }
59
+
60
+ this.config.onComplete?.(output)
61
+ return this.result!
62
+ } catch (err: any) {
63
+ const durationMs = Date.now() - start
64
+ this.result = {
65
+ id: this.config.id,
66
+ name: this.config.name,
67
+ type: this.config.type,
68
+ status: "failed",
69
+ input,
70
+ durationMs,
71
+ error: err.message,
72
+ }
73
+ this.config.onError?.(err)
74
+ return this.result!
75
+ }
76
+ }
77
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src"
6
+ },
7
+ "include": ["src"]
8
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from "tsup"
2
+ export default defineConfig({
3
+ entry: { index: "src/index.ts" },
4
+ format: ["cjs", "esm"],
5
+ dts: true,
6
+ sourcemap: true,
7
+ clean: true,
8
+ external: [/node_modules/],
9
+ })