@redtuma/core 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.
@@ -0,0 +1,199 @@
1
+ import { RuntimeContext } from "../types.js";
2
+ import { noopLogger } from "../logger.js";
3
+
4
+ //#region src/workflows/index.ts
5
+ function createStep(config) {
6
+ return { ...config };
7
+ }
8
+ var SuspendSignal = class {
9
+ constructor(stepId, payload) {
10
+ this.stepId = stepId;
11
+ this.payload = payload;
12
+ }
13
+ };
14
+ var Workflow = class {
15
+ id;
16
+ nodes = [];
17
+ committed = false;
18
+ logger = noopLogger;
19
+ constructor(config) {
20
+ this.config = config;
21
+ this.id = config.id;
22
+ }
23
+ then(step) {
24
+ this.nodes.push({
25
+ kind: "step",
26
+ step
27
+ });
28
+ return this;
29
+ }
30
+ parallel(steps) {
31
+ this.nodes.push({
32
+ kind: "parallel",
33
+ steps
34
+ });
35
+ return this;
36
+ }
37
+ branch(branches) {
38
+ this.nodes.push({
39
+ kind: "branch",
40
+ branches
41
+ });
42
+ return this;
43
+ }
44
+ dountil(step, condition) {
45
+ this.nodes.push({
46
+ kind: "dountil",
47
+ step,
48
+ condition
49
+ });
50
+ return this;
51
+ }
52
+ foreach(step) {
53
+ this.nodes.push({
54
+ kind: "foreach",
55
+ step
56
+ });
57
+ return this;
58
+ }
59
+ map(fn) {
60
+ this.nodes.push({
61
+ kind: "map",
62
+ fn
63
+ });
64
+ return this;
65
+ }
66
+ commit() {
67
+ this.committed = true;
68
+ return this;
69
+ }
70
+ createRun() {
71
+ if (!this.committed) throw new Error(`Workflow "${this.id}" must be committed with .commit() before running.`);
72
+ return new Run(this.id, this.nodes);
73
+ }
74
+ };
75
+ var Run = class {
76
+ snapshot = null;
77
+ constructor(workflowId, nodes) {
78
+ this.workflowId = workflowId;
79
+ this.nodes = nodes;
80
+ }
81
+ async start(args) {
82
+ const runtimeContext = args.runtimeContext ?? new RuntimeContext();
83
+ return this.execute(0, args.inputData, {}, runtimeContext, void 0);
84
+ }
85
+ async resume(args) {
86
+ if (!this.snapshot) throw new Error("Cannot resume: workflow is not suspended.");
87
+ if (this.snapshot.suspendedStepId !== args.step) throw new Error(`Cannot resume step "${args.step}": suspended step is "${this.snapshot.suspendedStepId}".`);
88
+ const { nodeIndex, input, results } = this.snapshot;
89
+ const runtimeContext = args.runtimeContext ?? new RuntimeContext();
90
+ this.snapshot = null;
91
+ return this.execute(nodeIndex, input, results, runtimeContext, args.resumeData);
92
+ }
93
+ async execute(startIndex, initialInput, results, runtimeContext, resumeData) {
94
+ let input = initialInput;
95
+ const getStepResult = (id) => results[id];
96
+ for (let i = startIndex; i < this.nodes.length; i++) {
97
+ const node = this.nodes[i];
98
+ const isResumeTarget = resumeData !== void 0 && i === startIndex;
99
+ const ctxBase = {
100
+ runtimeContext,
101
+ getStepResult
102
+ };
103
+ try {
104
+ switch (node.kind) {
105
+ case "step":
106
+ input = await this.runStep(node.step, input, ctxBase, isResumeTarget ? resumeData : void 0);
107
+ results[node.step.id] = input;
108
+ break;
109
+ case "parallel": {
110
+ const out = await Promise.all(node.steps.map((s) => this.runStep(s, input, ctxBase, void 0)));
111
+ const merged = {};
112
+ node.steps.forEach((s, idx) => {
113
+ results[s.id] = out[idx];
114
+ merged[s.id] = out[idx];
115
+ });
116
+ input = merged;
117
+ break;
118
+ }
119
+ case "branch":
120
+ for (const [cond, step] of node.branches) if (await cond({
121
+ inputData: input,
122
+ runtimeContext
123
+ })) {
124
+ input = await this.runStep(step, input, ctxBase, isResumeTarget ? resumeData : void 0);
125
+ results[step.id] = input;
126
+ break;
127
+ }
128
+ break;
129
+ case "dountil":
130
+ do {
131
+ input = await this.runStep(node.step, input, ctxBase, void 0);
132
+ results[node.step.id] = input;
133
+ } while (!await node.condition({
134
+ inputData: input,
135
+ runtimeContext
136
+ }));
137
+ break;
138
+ case "foreach": {
139
+ const items = Array.isArray(input) ? input : [input];
140
+ const out = [];
141
+ for (const item of items) out.push(await this.runStep(node.step, item, ctxBase, void 0));
142
+ input = out;
143
+ results[node.step.id] = out;
144
+ break;
145
+ }
146
+ case "map":
147
+ input = node.fn(input);
148
+ break;
149
+ }
150
+ resumeData = void 0;
151
+ } catch (err) {
152
+ if (err instanceof SuspendSignal) {
153
+ this.snapshot = {
154
+ nodeIndex: i,
155
+ input,
156
+ results,
157
+ suspendedStepId: err.stepId
158
+ };
159
+ return {
160
+ status: "suspended",
161
+ suspended: {
162
+ stepId: err.stepId,
163
+ payload: err.payload
164
+ },
165
+ steps: results
166
+ };
167
+ }
168
+ return {
169
+ status: "failed",
170
+ error: err,
171
+ steps: results
172
+ };
173
+ }
174
+ }
175
+ return {
176
+ status: "success",
177
+ result: input,
178
+ steps: results
179
+ };
180
+ }
181
+ async runStep(step, inputData, base, resumeData) {
182
+ const suspend = (payload) => {
183
+ throw new SuspendSignal(step.id, payload);
184
+ };
185
+ return step.execute({
186
+ inputData,
187
+ resumeData,
188
+ suspend,
189
+ ...base
190
+ });
191
+ }
192
+ };
193
+ function createWorkflow(config) {
194
+ return new Workflow(config);
195
+ }
196
+
197
+ //#endregion
198
+ export { Run, Workflow, createStep, createWorkflow };
199
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["stepId: string","payload: unknown","config: { id: string; inputSchema?: z.ZodTypeAny; outputSchema?: z.ZodTypeAny }","workflowId: string","nodes: Node[]","merged: Record<string, unknown>","out: unknown[]"],"sources":["../../src/workflows/index.ts"],"sourcesContent":["import type { z } from 'zod'\nimport { RuntimeContext, type Logger } from '../types'\nimport { noopLogger } from '../logger'\n\nexport interface StepExecuteContext<TInput = unknown, TResume = unknown> {\n inputData: TInput\n runtimeContext: RuntimeContext\n /** Result of a previously completed step by id. */\n getStepResult: (stepId: string) => unknown\n /** Data passed to `run.resume()` when resuming a suspended step. */\n resumeData?: TResume\n /** Suspend the workflow for human-in-the-loop; throws to halt execution. */\n suspend: (payload?: unknown) => never\n}\n\nexport interface Step<\n TInputSchema extends z.ZodTypeAny = z.ZodTypeAny,\n TOutputSchema extends z.ZodTypeAny = z.ZodTypeAny,\n> {\n id: string\n inputSchema?: TInputSchema\n outputSchema?: TOutputSchema\n resumeSchema?: z.ZodTypeAny\n suspendSchema?: z.ZodTypeAny\n execute: (ctx: StepExecuteContext) => Promise<unknown> | unknown\n}\n\nexport function createStep<\n TInputSchema extends z.ZodTypeAny = z.ZodTypeAny,\n TOutputSchema extends z.ZodTypeAny = z.ZodTypeAny,\n>(config: {\n id: string\n inputSchema?: TInputSchema\n outputSchema?: TOutputSchema\n resumeSchema?: z.ZodTypeAny\n suspendSchema?: z.ZodTypeAny\n execute: (ctx: StepExecuteContext) => Promise<unknown> | unknown\n}): Step<TInputSchema, TOutputSchema> {\n return { ...config }\n}\n\nclass SuspendSignal {\n constructor(\n public readonly stepId: string,\n public readonly payload: unknown,\n ) {}\n}\n\ntype Condition = (args: { inputData: unknown; runtimeContext: RuntimeContext }) => boolean | Promise<boolean>\n\ntype Node =\n | { kind: 'step'; step: Step }\n | { kind: 'parallel'; steps: Step[] }\n | { kind: 'branch'; branches: [Condition, Step][] }\n | { kind: 'dountil'; step: Step; condition: Condition }\n | { kind: 'foreach'; step: Step }\n | { kind: 'map'; fn: (input: unknown) => unknown }\n\nexport type RunStatus = 'success' | 'suspended' | 'failed'\n\nexport interface RunResult {\n status: RunStatus\n result?: unknown\n error?: Error\n suspended?: { stepId: string; payload: unknown }\n steps: Record<string, unknown>\n}\n\ninterface Snapshot {\n nodeIndex: number\n input: unknown\n results: Record<string, unknown>\n suspendedStepId: string\n}\n\nexport class Workflow {\n readonly id: string\n private nodes: Node[] = []\n private committed = false\n logger: Logger = noopLogger\n\n constructor(public config: { id: string; inputSchema?: z.ZodTypeAny; outputSchema?: z.ZodTypeAny }) {\n this.id = config.id\n }\n\n then(step: Step): this {\n this.nodes.push({ kind: 'step', step })\n return this\n }\n parallel(steps: Step[]): this {\n this.nodes.push({ kind: 'parallel', steps })\n return this\n }\n branch(branches: [Condition, Step][]): this {\n this.nodes.push({ kind: 'branch', branches })\n return this\n }\n dountil(step: Step, condition: Condition): this {\n this.nodes.push({ kind: 'dountil', step, condition })\n return this\n }\n foreach(step: Step): this {\n this.nodes.push({ kind: 'foreach', step })\n return this\n }\n map(fn: (input: unknown) => unknown): this {\n this.nodes.push({ kind: 'map', fn })\n return this\n }\n commit(): this {\n this.committed = true\n return this\n }\n\n createRun(): Run {\n if (!this.committed) {\n throw new Error(`Workflow \"${this.id}\" must be committed with .commit() before running.`)\n }\n return new Run(this.id, this.nodes)\n }\n}\n\nexport class Run {\n private snapshot: Snapshot | null = null\n\n constructor(\n public readonly workflowId: string,\n private readonly nodes: Node[],\n ) {}\n\n async start(args: { inputData: unknown; runtimeContext?: RuntimeContext }): Promise<RunResult> {\n const runtimeContext = args.runtimeContext ?? new RuntimeContext()\n return this.execute(0, args.inputData, {}, runtimeContext, undefined)\n }\n\n async resume(args: {\n step: string\n resumeData?: unknown\n runtimeContext?: RuntimeContext\n }): Promise<RunResult> {\n if (!this.snapshot) throw new Error('Cannot resume: workflow is not suspended.')\n if (this.snapshot.suspendedStepId !== args.step) {\n throw new Error(\n `Cannot resume step \"${args.step}\": suspended step is \"${this.snapshot.suspendedStepId}\".`,\n )\n }\n const { nodeIndex, input, results } = this.snapshot\n const runtimeContext = args.runtimeContext ?? new RuntimeContext()\n this.snapshot = null\n return this.execute(nodeIndex, input, results, runtimeContext, args.resumeData)\n }\n\n private async execute(\n startIndex: number,\n initialInput: unknown,\n results: Record<string, unknown>,\n runtimeContext: RuntimeContext,\n resumeData: unknown,\n ): Promise<RunResult> {\n let input = initialInput\n const getStepResult = (id: string) => results[id]\n\n for (let i = startIndex; i < this.nodes.length; i++) {\n const node = this.nodes[i]!\n const isResumeTarget = resumeData !== undefined && i === startIndex\n const ctxBase = { runtimeContext, getStepResult }\n\n try {\n switch (node.kind) {\n case 'step': {\n input = await this.runStep(node.step, input, ctxBase, isResumeTarget ? resumeData : undefined)\n results[node.step.id] = input\n break\n }\n case 'parallel': {\n const out = await Promise.all(\n node.steps.map((s) => this.runStep(s, input, ctxBase, undefined)),\n )\n const merged: Record<string, unknown> = {}\n node.steps.forEach((s, idx) => {\n results[s.id] = out[idx]\n merged[s.id] = out[idx]\n })\n input = merged\n break\n }\n case 'branch': {\n for (const [cond, step] of node.branches) {\n if (await cond({ inputData: input, runtimeContext })) {\n input = await this.runStep(step, input, ctxBase, isResumeTarget ? resumeData : undefined)\n results[step.id] = input\n break\n }\n }\n break\n }\n case 'dountil': {\n do {\n input = await this.runStep(node.step, input, ctxBase, undefined)\n results[node.step.id] = input\n } while (!(await node.condition({ inputData: input, runtimeContext })))\n break\n }\n case 'foreach': {\n const items = Array.isArray(input) ? input : [input]\n const out: unknown[] = []\n for (const item of items) {\n out.push(await this.runStep(node.step, item, ctxBase, undefined))\n }\n input = out\n results[node.step.id] = out\n break\n }\n case 'map': {\n input = node.fn(input)\n break\n }\n }\n resumeData = undefined\n } catch (err) {\n if (err instanceof SuspendSignal) {\n this.snapshot = {\n nodeIndex: i,\n input,\n results,\n suspendedStepId: err.stepId,\n }\n return { status: 'suspended', suspended: { stepId: err.stepId, payload: err.payload }, steps: results }\n }\n return { status: 'failed', error: err as Error, steps: results }\n }\n }\n\n return { status: 'success', result: input, steps: results }\n }\n\n private async runStep(\n step: Step,\n inputData: unknown,\n base: { runtimeContext: RuntimeContext; getStepResult: (id: string) => unknown },\n resumeData: unknown,\n ): Promise<unknown> {\n const suspend = (payload?: unknown): never => {\n throw new SuspendSignal(step.id, payload)\n }\n return step.execute({ inputData, resumeData, suspend, ...base })\n }\n}\n\nexport function createWorkflow(config: {\n id: string\n inputSchema?: z.ZodTypeAny\n outputSchema?: z.ZodTypeAny\n}): Workflow {\n return new Workflow(config)\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@redtuma/core",
3
+ "version": "0.1.0",
4
+ "description": "Redtuma core: the Redtuma registry, Agent, tools, model routing and workflow engine.",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ },
16
+ "./agent": {
17
+ "types": "./dist/agent/index.d.ts",
18
+ "import": "./dist/agent/index.js"
19
+ },
20
+ "./tools": {
21
+ "types": "./dist/tools/index.d.ts",
22
+ "import": "./dist/tools/index.js"
23
+ },
24
+ "./workflows": {
25
+ "types": "./dist/workflows/index.d.ts",
26
+ "import": "./dist/workflows/index.js"
27
+ },
28
+ "./llm": {
29
+ "types": "./dist/llm/index.d.ts",
30
+ "import": "./dist/llm/index.js"
31
+ },
32
+ "./store": {
33
+ "types": "./dist/store/index.d.ts",
34
+ "import": "./dist/store/index.js"
35
+ }
36
+ },
37
+ "dependencies": {
38
+ "ai": "^4.3.0",
39
+ "zod": "^3.24.0"
40
+ },
41
+ "peerDependencies": {
42
+ "@ai-sdk/anthropic": "^1.2.0",
43
+ "@ai-sdk/openai": "^1.3.0"
44
+ },
45
+ "peerDependenciesMeta": {
46
+ "@ai-sdk/anthropic": {
47
+ "optional": true
48
+ },
49
+ "@ai-sdk/openai": {
50
+ "optional": true
51
+ }
52
+ },
53
+ "devDependencies": {
54
+ "@ai-sdk/anthropic": "^1.2.0",
55
+ "@ai-sdk/openai": "^1.3.0",
56
+ "@ai-sdk/provider": "^1.1.0"
57
+ },
58
+ "repository": {
59
+ "type": "git",
60
+ "url": "git+https://github.com/redtuma-ai/redtuma.git",
61
+ "directory": "packages/core"
62
+ },
63
+ "homepage": "https://redtuma.ai",
64
+ "bugs": "https://github.com/redtuma-ai/redtuma/issues",
65
+ "keywords": [
66
+ "ai",
67
+ "agents",
68
+ "llm",
69
+ "typescript",
70
+ "redtuma",
71
+ "vercel-ai-sdk"
72
+ ],
73
+ "scripts": {
74
+ "build": "tsdown",
75
+ "test": "vitest run",
76
+ "test:watch": "vitest",
77
+ "typecheck": "tsc --noEmit",
78
+ "clean": "rm -rf dist .turbo"
79
+ }
80
+ }