veryfront 0.0.7 → 0.0.10
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/ai/index.js +408 -53
- package/dist/ai/index.js.map +4 -4
- package/dist/ai/react.d.ts +103 -2
- package/dist/cli.js +5098 -1444
- package/dist/components.js +166 -78
- package/dist/components.js.map +4 -4
- package/dist/config.js +20 -5
- package/dist/config.js.map +3 -3
- package/dist/data.js +20 -2
- package/dist/data.js.map +4 -4
- package/dist/index.js +195 -89
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/ai/index.js
CHANGED
|
@@ -844,17 +844,30 @@ var GoogleProvider = class extends BaseProvider {
|
|
|
844
844
|
}
|
|
845
845
|
};
|
|
846
846
|
|
|
847
|
-
// src/
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
847
|
+
// src/platform/compat/process.ts
|
|
848
|
+
import process from "node:process";
|
|
849
|
+
|
|
850
|
+
// src/platform/compat/runtime.ts
|
|
851
|
+
var isDeno = typeof Deno !== "undefined";
|
|
852
|
+
var isNode = typeof globalThis.process !== "undefined" && globalThis.process?.versions?.node !== void 0;
|
|
853
|
+
var isBun = typeof globalThis.Bun !== "undefined";
|
|
854
|
+
var isCloudflare = typeof globalThis !== "undefined" && "caches" in globalThis && "WebSocketPair" in globalThis;
|
|
855
|
+
|
|
856
|
+
// src/platform/compat/process.ts
|
|
857
|
+
function cwd() {
|
|
858
|
+
if (isDeno) {
|
|
859
|
+
return process.cwd();
|
|
851
860
|
}
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
861
|
+
return process.cwd();
|
|
862
|
+
}
|
|
863
|
+
function getEnv(key) {
|
|
864
|
+
if (isDeno) {
|
|
865
|
+
return process.env(key);
|
|
855
866
|
}
|
|
856
|
-
return
|
|
867
|
+
return process.env[key];
|
|
857
868
|
}
|
|
869
|
+
|
|
870
|
+
// src/ai/providers/factory.ts
|
|
858
871
|
var ProviderRegistry = class {
|
|
859
872
|
constructor() {
|
|
860
873
|
this.providers = /* @__PURE__ */ new Map();
|
|
@@ -1675,7 +1688,7 @@ var BYTES_PER_MB = 1024 * 1024;
|
|
|
1675
1688
|
// deno.json
|
|
1676
1689
|
var deno_default = {
|
|
1677
1690
|
name: "veryfront",
|
|
1678
|
-
version: "0.0.
|
|
1691
|
+
version: "0.0.10",
|
|
1679
1692
|
nodeModulesDir: "auto",
|
|
1680
1693
|
workspace: [
|
|
1681
1694
|
"./examples/async-worker-redis",
|
|
@@ -1804,6 +1817,7 @@ var deno_default = {
|
|
|
1804
1817
|
dev: "deno run --allow-all --no-lock --unstable-net --unstable-worker-options src/cli/main.ts dev",
|
|
1805
1818
|
build: "deno compile --allow-all --output ../../bin/veryfront src/cli/main.ts",
|
|
1806
1819
|
"build:npm": "deno run -A scripts/build-npm.ts",
|
|
1820
|
+
release: "deno run -A scripts/release.ts",
|
|
1807
1821
|
test: "DENO_JOBS=1 deno test --parallel --fail-fast --allow-all --unstable-worker-options --unstable-net",
|
|
1808
1822
|
"test:unit": "DENO_JOBS=1 deno test --parallel --allow-all --v8-flags=--max-old-space-size=8192 --ignore=tests --unstable-worker-options --unstable-net",
|
|
1809
1823
|
"test:integration": "DENO_JOBS=1 deno test --parallel --fail-fast --allow-all tests --unstable-worker-options --unstable-net",
|
|
@@ -3466,6 +3480,7 @@ var DEFAULT_CONFIG2 = {
|
|
|
3466
3480
|
}
|
|
3467
3481
|
};
|
|
3468
3482
|
var configCacheByProject = /* @__PURE__ */ new Map();
|
|
3483
|
+
var cacheRevision = 0;
|
|
3469
3484
|
function validateCorsConfig(userConfig) {
|
|
3470
3485
|
if (!userConfig || typeof userConfig !== "object") {
|
|
3471
3486
|
return;
|
|
@@ -3542,13 +3557,18 @@ var ConfigValidationError = class extends Error {
|
|
|
3542
3557
|
};
|
|
3543
3558
|
async function loadAndMergeConfig(configPath, projectDir) {
|
|
3544
3559
|
try {
|
|
3545
|
-
const configUrl = `file://${configPath}?t=${Date.now()}`;
|
|
3560
|
+
const configUrl = `file://${configPath}?t=${Date.now()}-${crypto.randomUUID()}`;
|
|
3546
3561
|
const configModule = await import(configUrl);
|
|
3547
3562
|
const userConfig = configModule.default || configModule;
|
|
3563
|
+
if (userConfig === null || typeof userConfig !== "object" || Array.isArray(userConfig)) {
|
|
3564
|
+
throw new ConfigValidationError(
|
|
3565
|
+
`Expected object, received ${userConfig === null ? "null" : typeof userConfig}`
|
|
3566
|
+
);
|
|
3567
|
+
}
|
|
3548
3568
|
validateCorsConfig(userConfig);
|
|
3549
3569
|
validateConfigShape(userConfig);
|
|
3550
3570
|
const merged = mergeConfigs(userConfig);
|
|
3551
|
-
configCacheByProject.set(projectDir, merged);
|
|
3571
|
+
configCacheByProject.set(projectDir, { revision: cacheRevision, config: merged });
|
|
3552
3572
|
return merged;
|
|
3553
3573
|
} catch (error) {
|
|
3554
3574
|
if (error instanceof ConfigValidationError) {
|
|
@@ -3562,8 +3582,8 @@ async function loadAndMergeConfig(configPath, projectDir) {
|
|
|
3562
3582
|
}
|
|
3563
3583
|
async function getConfig(projectDir, adapter) {
|
|
3564
3584
|
const cached = configCacheByProject.get(projectDir);
|
|
3565
|
-
if (cached)
|
|
3566
|
-
return cached;
|
|
3585
|
+
if (cached && cached.revision === cacheRevision)
|
|
3586
|
+
return cached.config;
|
|
3567
3587
|
const configFiles = ["veryfront.config.js", "veryfront.config.ts", "veryfront.config.mjs"];
|
|
3568
3588
|
for (const configFile of configFiles) {
|
|
3569
3589
|
const configPath = join(projectDir, configFile);
|
|
@@ -3589,7 +3609,7 @@ async function getConfig(projectDir, adapter) {
|
|
|
3589
3609
|
}
|
|
3590
3610
|
}
|
|
3591
3611
|
const defaultConfig = DEFAULT_CONFIG2;
|
|
3592
|
-
configCacheByProject.set(projectDir, defaultConfig);
|
|
3612
|
+
configCacheByProject.set(projectDir, { revision: cacheRevision, config: defaultConfig });
|
|
3593
3613
|
return defaultConfig;
|
|
3594
3614
|
}
|
|
3595
3615
|
|
|
@@ -3638,16 +3658,16 @@ function createMockAdapter() {
|
|
|
3638
3658
|
files.set(path, content);
|
|
3639
3659
|
return Promise.resolve();
|
|
3640
3660
|
},
|
|
3641
|
-
exists:
|
|
3661
|
+
exists: (path) => {
|
|
3642
3662
|
if (files.has(path))
|
|
3643
|
-
return true;
|
|
3663
|
+
return Promise.resolve(true);
|
|
3644
3664
|
if (directories.has(path))
|
|
3645
|
-
return true;
|
|
3665
|
+
return Promise.resolve(true);
|
|
3646
3666
|
for (const filePath of files.keys()) {
|
|
3647
3667
|
if (filePath.startsWith(path + "/"))
|
|
3648
|
-
return true;
|
|
3668
|
+
return Promise.resolve(true);
|
|
3649
3669
|
}
|
|
3650
|
-
return false;
|
|
3670
|
+
return Promise.resolve(false);
|
|
3651
3671
|
},
|
|
3652
3672
|
readDir: async function* (path) {
|
|
3653
3673
|
const entries = /* @__PURE__ */ new Map();
|
|
@@ -3925,14 +3945,14 @@ async function findTypeScriptFiles(dir, context) {
|
|
|
3925
3945
|
}
|
|
3926
3946
|
}
|
|
3927
3947
|
} else {
|
|
3928
|
-
const { fs, path } = await getNodeDeps(context);
|
|
3929
|
-
if (!
|
|
3948
|
+
const { fs: fs2, path } = await getNodeDeps(context);
|
|
3949
|
+
if (!fs2 || !path) {
|
|
3930
3950
|
return files;
|
|
3931
3951
|
}
|
|
3932
|
-
if (!
|
|
3952
|
+
if (!fs2.existsSync(dir)) {
|
|
3933
3953
|
return files;
|
|
3934
3954
|
}
|
|
3935
|
-
const entries =
|
|
3955
|
+
const entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
3936
3956
|
for (const entry of entries) {
|
|
3937
3957
|
const filePath = path.join(dir, entry.name);
|
|
3938
3958
|
if (entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx"))) {
|
|
@@ -4030,10 +4050,165 @@ function toAISDKTools(tools) {
|
|
|
4030
4050
|
return aiTools;
|
|
4031
4051
|
}
|
|
4032
4052
|
|
|
4053
|
+
// src/platform/compat/fs.ts
|
|
4054
|
+
var NodeFileSystem = class {
|
|
4055
|
+
constructor() {
|
|
4056
|
+
this.fs = null;
|
|
4057
|
+
this.os = null;
|
|
4058
|
+
this.path = null;
|
|
4059
|
+
this.initialized = false;
|
|
4060
|
+
}
|
|
4061
|
+
async ensureInitialized() {
|
|
4062
|
+
if (this.initialized)
|
|
4063
|
+
return;
|
|
4064
|
+
if (!isNode) {
|
|
4065
|
+
throw toError(createError({
|
|
4066
|
+
type: "not_supported",
|
|
4067
|
+
message: "Node.js fs modules not available",
|
|
4068
|
+
feature: "Node.js"
|
|
4069
|
+
}));
|
|
4070
|
+
}
|
|
4071
|
+
const [fsModule, osModule, pathModule] = await Promise.all([
|
|
4072
|
+
import("node:fs/promises"),
|
|
4073
|
+
import("node:os"),
|
|
4074
|
+
import("node:path")
|
|
4075
|
+
]);
|
|
4076
|
+
this.fs = fsModule;
|
|
4077
|
+
this.os = osModule;
|
|
4078
|
+
this.path = pathModule;
|
|
4079
|
+
this.initialized = true;
|
|
4080
|
+
}
|
|
4081
|
+
async readTextFile(path) {
|
|
4082
|
+
await this.ensureInitialized();
|
|
4083
|
+
return await this.fs.readFile(path, { encoding: "utf8" });
|
|
4084
|
+
}
|
|
4085
|
+
async readFile(path) {
|
|
4086
|
+
await this.ensureInitialized();
|
|
4087
|
+
return await this.fs.readFile(path);
|
|
4088
|
+
}
|
|
4089
|
+
async writeTextFile(path, data) {
|
|
4090
|
+
await this.ensureInitialized();
|
|
4091
|
+
await this.fs.writeFile(path, data, { encoding: "utf8" });
|
|
4092
|
+
}
|
|
4093
|
+
async writeFile(path, data) {
|
|
4094
|
+
await this.ensureInitialized();
|
|
4095
|
+
await this.fs.writeFile(path, data);
|
|
4096
|
+
}
|
|
4097
|
+
async exists(path) {
|
|
4098
|
+
await this.ensureInitialized();
|
|
4099
|
+
try {
|
|
4100
|
+
await this.fs.access(path);
|
|
4101
|
+
return true;
|
|
4102
|
+
} catch (error) {
|
|
4103
|
+
if (error.code === "ENOENT") {
|
|
4104
|
+
return false;
|
|
4105
|
+
}
|
|
4106
|
+
throw error;
|
|
4107
|
+
}
|
|
4108
|
+
}
|
|
4109
|
+
async stat(path) {
|
|
4110
|
+
await this.ensureInitialized();
|
|
4111
|
+
const stat = await this.fs.stat(path);
|
|
4112
|
+
return {
|
|
4113
|
+
isFile: stat.isFile(),
|
|
4114
|
+
isDirectory: stat.isDirectory(),
|
|
4115
|
+
isSymlink: stat.isSymbolicLink(),
|
|
4116
|
+
size: stat.size,
|
|
4117
|
+
mtime: stat.mtime
|
|
4118
|
+
};
|
|
4119
|
+
}
|
|
4120
|
+
async mkdir(path, options) {
|
|
4121
|
+
await this.ensureInitialized();
|
|
4122
|
+
await this.fs.mkdir(path, { recursive: options?.recursive ?? false });
|
|
4123
|
+
}
|
|
4124
|
+
async *readDir(path) {
|
|
4125
|
+
await this.ensureInitialized();
|
|
4126
|
+
const entries = await this.fs.readdir(path, { withFileTypes: true });
|
|
4127
|
+
for (const entry of entries) {
|
|
4128
|
+
yield {
|
|
4129
|
+
name: entry.name,
|
|
4130
|
+
isFile: entry.isFile(),
|
|
4131
|
+
isDirectory: entry.isDirectory()
|
|
4132
|
+
};
|
|
4133
|
+
}
|
|
4134
|
+
}
|
|
4135
|
+
async remove(path, options) {
|
|
4136
|
+
await this.ensureInitialized();
|
|
4137
|
+
await this.fs.rm(path, { recursive: options?.recursive ?? false, force: options?.recursive ?? false });
|
|
4138
|
+
}
|
|
4139
|
+
async makeTempDir(options) {
|
|
4140
|
+
await this.ensureInitialized();
|
|
4141
|
+
const tempDir = this.path.join(this.os.tmpdir(), `${options?.prefix ?? "tmp-"}${Math.random().toString(36).substring(2, 8)}`);
|
|
4142
|
+
await this.fs.mkdir(tempDir, { recursive: true });
|
|
4143
|
+
return tempDir;
|
|
4144
|
+
}
|
|
4145
|
+
};
|
|
4146
|
+
var DenoFileSystem = class {
|
|
4147
|
+
async readTextFile(path) {
|
|
4148
|
+
return await Deno.readTextFile(path);
|
|
4149
|
+
}
|
|
4150
|
+
async readFile(path) {
|
|
4151
|
+
return await Deno.readFile(path);
|
|
4152
|
+
}
|
|
4153
|
+
async writeTextFile(path, data) {
|
|
4154
|
+
await Deno.writeTextFile(path, data);
|
|
4155
|
+
}
|
|
4156
|
+
async writeFile(path, data) {
|
|
4157
|
+
await Deno.writeFile(path, data);
|
|
4158
|
+
}
|
|
4159
|
+
async exists(path) {
|
|
4160
|
+
try {
|
|
4161
|
+
await Deno.stat(path);
|
|
4162
|
+
return true;
|
|
4163
|
+
} catch (error) {
|
|
4164
|
+
if (error instanceof Deno.errors.NotFound) {
|
|
4165
|
+
return false;
|
|
4166
|
+
}
|
|
4167
|
+
throw error;
|
|
4168
|
+
}
|
|
4169
|
+
}
|
|
4170
|
+
async stat(path) {
|
|
4171
|
+
const stat = await Deno.stat(path);
|
|
4172
|
+
return {
|
|
4173
|
+
isFile: stat.isFile,
|
|
4174
|
+
isDirectory: stat.isDirectory,
|
|
4175
|
+
isSymlink: stat.isSymlink,
|
|
4176
|
+
size: stat.size,
|
|
4177
|
+
mtime: stat.mtime
|
|
4178
|
+
};
|
|
4179
|
+
}
|
|
4180
|
+
async mkdir(path, options) {
|
|
4181
|
+
await Deno.mkdir(path, { recursive: options?.recursive ?? false });
|
|
4182
|
+
}
|
|
4183
|
+
async *readDir(path) {
|
|
4184
|
+
for await (const entry of Deno.readDir(path)) {
|
|
4185
|
+
yield {
|
|
4186
|
+
name: entry.name,
|
|
4187
|
+
isFile: entry.isFile,
|
|
4188
|
+
isDirectory: entry.isDirectory
|
|
4189
|
+
};
|
|
4190
|
+
}
|
|
4191
|
+
}
|
|
4192
|
+
async remove(path, options) {
|
|
4193
|
+
await Deno.remove(path, { recursive: options?.recursive ?? false });
|
|
4194
|
+
}
|
|
4195
|
+
async makeTempDir(options) {
|
|
4196
|
+
return await Deno.makeTempDir({ prefix: options?.prefix });
|
|
4197
|
+
}
|
|
4198
|
+
};
|
|
4199
|
+
function createFileSystem() {
|
|
4200
|
+
if (isDeno) {
|
|
4201
|
+
return new DenoFileSystem();
|
|
4202
|
+
} else {
|
|
4203
|
+
return new NodeFileSystem();
|
|
4204
|
+
}
|
|
4205
|
+
}
|
|
4206
|
+
|
|
4033
4207
|
// src/ai/utils/setup.ts
|
|
4208
|
+
var fs = createFileSystem();
|
|
4034
4209
|
async function setupAI(options = {}) {
|
|
4035
4210
|
const {
|
|
4036
|
-
baseDir =
|
|
4211
|
+
baseDir = cwd(),
|
|
4037
4212
|
aiDir = "ai",
|
|
4038
4213
|
tools: manualTools = {},
|
|
4039
4214
|
agents: manualAgents = {},
|
|
@@ -4050,7 +4225,7 @@ async function setupAI(options = {}) {
|
|
|
4050
4225
|
const errors = [];
|
|
4051
4226
|
if (manifestPath) {
|
|
4052
4227
|
try {
|
|
4053
|
-
const manifest = await
|
|
4228
|
+
const manifest = await fs.readTextFile(manifestPath).then(JSON.parse);
|
|
4054
4229
|
if (manifest.tools) {
|
|
4055
4230
|
for (const [id, tool2] of Object.entries(manifest.tools)) {
|
|
4056
4231
|
tools.set(id, tool2);
|
|
@@ -4076,7 +4251,7 @@ async function setupAI(options = {}) {
|
|
|
4076
4251
|
}
|
|
4077
4252
|
}
|
|
4078
4253
|
if (verbose) {
|
|
4079
|
-
|
|
4254
|
+
cliLogger.info(`[setupAI] Loaded manifest: ${tools.size} tools, ${agents.size} agents`);
|
|
4080
4255
|
}
|
|
4081
4256
|
} catch (error) {
|
|
4082
4257
|
errors.push({
|
|
@@ -4107,11 +4282,11 @@ async function setupAI(options = {}) {
|
|
|
4107
4282
|
}
|
|
4108
4283
|
errors.push(...discovered.errors);
|
|
4109
4284
|
if (verbose) {
|
|
4110
|
-
|
|
4285
|
+
cliLogger.info(`[setupAI] Discovered: ${tools.size} tools, ${agents.size} agents`);
|
|
4111
4286
|
}
|
|
4112
4287
|
} catch (error) {
|
|
4113
4288
|
if (verbose) {
|
|
4114
|
-
|
|
4289
|
+
cliLogger.info(`[setupAI] Discovery skipped: ${error}`);
|
|
4115
4290
|
}
|
|
4116
4291
|
}
|
|
4117
4292
|
}
|
|
@@ -4159,24 +4334,6 @@ async function setupAI(options = {}) {
|
|
|
4159
4334
|
};
|
|
4160
4335
|
return result;
|
|
4161
4336
|
}
|
|
4162
|
-
function detectCwd() {
|
|
4163
|
-
if (typeof Deno !== "undefined" && typeof process.cwd === "function") {
|
|
4164
|
-
return process.cwd();
|
|
4165
|
-
}
|
|
4166
|
-
if (typeof process !== "undefined" && typeof process.cwd === "function") {
|
|
4167
|
-
return process.cwd();
|
|
4168
|
-
}
|
|
4169
|
-
return ".";
|
|
4170
|
-
}
|
|
4171
|
-
async function loadManifest(path) {
|
|
4172
|
-
if (typeof Deno !== "undefined" && typeof Deno.readTextFile === "function") {
|
|
4173
|
-
const content2 = await Deno.readTextFile(path);
|
|
4174
|
-
return JSON.parse(content2);
|
|
4175
|
-
}
|
|
4176
|
-
const fs = await import("node:fs/promises");
|
|
4177
|
-
const content = await fs.readFile(path, "utf-8");
|
|
4178
|
-
return JSON.parse(content);
|
|
4179
|
-
}
|
|
4180
4337
|
|
|
4181
4338
|
// src/ai/mcp/server.ts
|
|
4182
4339
|
var MCPServer = class {
|
|
@@ -5448,6 +5605,23 @@ function waitForApproval(id, options = {}) {
|
|
|
5448
5605
|
};
|
|
5449
5606
|
}
|
|
5450
5607
|
|
|
5608
|
+
// src/platform/compat/path-helper.ts
|
|
5609
|
+
import nodePath from "node:path";
|
|
5610
|
+
var pathMod = null;
|
|
5611
|
+
var denoPathPromise = null;
|
|
5612
|
+
if (typeof Deno === "undefined") {
|
|
5613
|
+
pathMod = nodePath;
|
|
5614
|
+
} else {
|
|
5615
|
+
denoPathPromise = import("path").then((mod) => {
|
|
5616
|
+
pathMod = mod;
|
|
5617
|
+
return pathMod;
|
|
5618
|
+
});
|
|
5619
|
+
}
|
|
5620
|
+
var sep = nodePath.sep;
|
|
5621
|
+
|
|
5622
|
+
// src/ai/workflow/blob/s3-storage.ts
|
|
5623
|
+
import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, HeadObjectCommand, CreateBucketCommand } from "@aws-sdk/client-s3";
|
|
5624
|
+
|
|
5451
5625
|
// src/ai/workflow/backends/types.ts
|
|
5452
5626
|
function hasLockSupport(backend) {
|
|
5453
5627
|
return typeof backend.acquireLock === "function" && typeof backend.releaseLock === "function";
|
|
@@ -5788,6 +5962,15 @@ var MemoryBackend = class {
|
|
|
5788
5962
|
}
|
|
5789
5963
|
};
|
|
5790
5964
|
|
|
5965
|
+
// src/ai/workflow/backends/redis.ts
|
|
5966
|
+
var DenoRedis = void 0;
|
|
5967
|
+
var NodeRedis = void 0;
|
|
5968
|
+
if (typeof Deno !== "undefined") {
|
|
5969
|
+
DenoRedis = await import("redis");
|
|
5970
|
+
} else {
|
|
5971
|
+
NodeRedis = await import("redis");
|
|
5972
|
+
}
|
|
5973
|
+
|
|
5791
5974
|
// src/ai/workflow/executor/dag-executor.ts
|
|
5792
5975
|
var DAGExecutor = class {
|
|
5793
5976
|
constructor(config) {
|
|
@@ -5921,20 +6104,172 @@ var DAGExecutor = class {
|
|
|
5921
6104
|
return await this.executeStepNode(node, context);
|
|
5922
6105
|
case "parallel":
|
|
5923
6106
|
return await this.executeParallelNode(node, config, context, nodeStates);
|
|
6107
|
+
case "map":
|
|
6108
|
+
return await this.executeMapNode(node, config, context, nodeStates);
|
|
5924
6109
|
case "branch":
|
|
5925
6110
|
return await this.executeBranchNode(node, config, context, nodeStates);
|
|
5926
6111
|
case "wait":
|
|
5927
6112
|
return await this.executeWaitNode(node, config, context);
|
|
5928
6113
|
case "subWorkflow":
|
|
5929
|
-
|
|
5930
|
-
`Sub-workflow execution is not yet implemented for node "${node.id}". Workaround: Flatten your workflow by inlining the sub-workflow steps directly, or use the parallel() or branch() DSL helpers to compose workflows.`
|
|
5931
|
-
);
|
|
6114
|
+
return await this.executeSubWorkflowNode(node, config, context, nodeStates);
|
|
5932
6115
|
default:
|
|
5933
6116
|
throw new Error(
|
|
5934
|
-
`Unknown node type "${config.type}" for node "${node.id}". Valid types are: step, parallel, branch, wait, subWorkflow`
|
|
6117
|
+
`Unknown node type "${config.type}" for node "${node.id}". Valid types are: step, parallel, map, branch, wait, subWorkflow`
|
|
5935
6118
|
);
|
|
5936
6119
|
}
|
|
5937
6120
|
}
|
|
6121
|
+
/**
|
|
6122
|
+
* Execute a map node (dynamic fan-out)
|
|
6123
|
+
*/
|
|
6124
|
+
async executeMapNode(node, config, context, nodeStates) {
|
|
6125
|
+
const startTime = Date.now();
|
|
6126
|
+
const items = typeof config.items === "function" ? await config.items(context) : config.items;
|
|
6127
|
+
if (!Array.isArray(items)) {
|
|
6128
|
+
throw new Error(`Map node "${node.id}" items must be an array`);
|
|
6129
|
+
}
|
|
6130
|
+
if (items.length === 0) {
|
|
6131
|
+
const state = {
|
|
6132
|
+
nodeId: node.id,
|
|
6133
|
+
status: "completed",
|
|
6134
|
+
output: [],
|
|
6135
|
+
attempt: 1,
|
|
6136
|
+
startedAt: new Date(startTime),
|
|
6137
|
+
completedAt: /* @__PURE__ */ new Date()
|
|
6138
|
+
};
|
|
6139
|
+
return { state, contextUpdates: { [node.id]: [] }, waiting: false };
|
|
6140
|
+
}
|
|
6141
|
+
const childNodes = [];
|
|
6142
|
+
const isWorkflowDef = (p) => !!p.steps;
|
|
6143
|
+
for (let i = 0; i < items.length; i++) {
|
|
6144
|
+
const item = items[i];
|
|
6145
|
+
const childId = `${node.id}_${i}`;
|
|
6146
|
+
let childNode;
|
|
6147
|
+
if (isWorkflowDef(config.processor)) {
|
|
6148
|
+
childNode = {
|
|
6149
|
+
id: childId,
|
|
6150
|
+
config: {
|
|
6151
|
+
type: "subWorkflow",
|
|
6152
|
+
workflow: config.processor,
|
|
6153
|
+
input: item,
|
|
6154
|
+
retry: config.retry,
|
|
6155
|
+
checkpoint: false
|
|
6156
|
+
// Don't checkpoint individual map items by default
|
|
6157
|
+
}
|
|
6158
|
+
};
|
|
6159
|
+
} else {
|
|
6160
|
+
const processorConfig = { ...config.processor.config };
|
|
6161
|
+
if (processorConfig.type === "step") {
|
|
6162
|
+
processorConfig.input = item;
|
|
6163
|
+
}
|
|
6164
|
+
childNode = {
|
|
6165
|
+
id: childId,
|
|
6166
|
+
config: processorConfig
|
|
6167
|
+
};
|
|
6168
|
+
}
|
|
6169
|
+
childNodes.push(childNode);
|
|
6170
|
+
}
|
|
6171
|
+
const originalConcurrency = this.config.maxConcurrency;
|
|
6172
|
+
if (config.concurrency) {
|
|
6173
|
+
this.config.maxConcurrency = config.concurrency;
|
|
6174
|
+
}
|
|
6175
|
+
try {
|
|
6176
|
+
const result = await this.execute(childNodes, {
|
|
6177
|
+
id: `${node.id}_map`,
|
|
6178
|
+
workflowId: "",
|
|
6179
|
+
status: "running",
|
|
6180
|
+
input: context.input,
|
|
6181
|
+
nodeStates: {},
|
|
6182
|
+
// Start fresh for map iteration
|
|
6183
|
+
currentNodes: [],
|
|
6184
|
+
context: { ...context },
|
|
6185
|
+
// Pass copy of context so they can read global state
|
|
6186
|
+
checkpoints: [],
|
|
6187
|
+
pendingApprovals: [],
|
|
6188
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
6189
|
+
});
|
|
6190
|
+
Object.assign(nodeStates, result.nodeStates);
|
|
6191
|
+
const outputs = childNodes.map((child) => {
|
|
6192
|
+
const childState = result.nodeStates[child.id];
|
|
6193
|
+
return childState?.output;
|
|
6194
|
+
});
|
|
6195
|
+
const state = {
|
|
6196
|
+
nodeId: node.id,
|
|
6197
|
+
status: result.completed ? "completed" : result.waiting ? "running" : "failed",
|
|
6198
|
+
output: outputs,
|
|
6199
|
+
error: result.error,
|
|
6200
|
+
attempt: 1,
|
|
6201
|
+
startedAt: new Date(startTime),
|
|
6202
|
+
completedAt: result.completed ? /* @__PURE__ */ new Date() : void 0
|
|
6203
|
+
};
|
|
6204
|
+
this.config.onNodeComplete?.(node.id, state);
|
|
6205
|
+
return {
|
|
6206
|
+
state,
|
|
6207
|
+
contextUpdates: result.completed ? { [node.id]: outputs } : {},
|
|
6208
|
+
waiting: result.waiting
|
|
6209
|
+
};
|
|
6210
|
+
} finally {
|
|
6211
|
+
this.config.maxConcurrency = originalConcurrency;
|
|
6212
|
+
}
|
|
6213
|
+
}
|
|
6214
|
+
/**
|
|
6215
|
+
* Execute a sub-workflow node
|
|
6216
|
+
*/
|
|
6217
|
+
async executeSubWorkflowNode(node, config, context, _nodeStates) {
|
|
6218
|
+
const startTime = Date.now();
|
|
6219
|
+
let workflowDef;
|
|
6220
|
+
if (typeof config.workflow === "string") {
|
|
6221
|
+
throw new Error("Resolving workflow by ID is not yet supported in this execution context. Pass the WorkflowDefinition object.");
|
|
6222
|
+
} else {
|
|
6223
|
+
workflowDef = config.workflow;
|
|
6224
|
+
}
|
|
6225
|
+
const input = typeof config.input === "function" ? await config.input(context) : config.input ?? context.input;
|
|
6226
|
+
let steps;
|
|
6227
|
+
if (typeof workflowDef.steps === "function") {
|
|
6228
|
+
steps = workflowDef.steps({
|
|
6229
|
+
input,
|
|
6230
|
+
context
|
|
6231
|
+
});
|
|
6232
|
+
} else {
|
|
6233
|
+
steps = workflowDef.steps;
|
|
6234
|
+
}
|
|
6235
|
+
const subRunId = `${node.id}_sub_${generateId()}`;
|
|
6236
|
+
const result = await this.execute(steps, {
|
|
6237
|
+
id: subRunId,
|
|
6238
|
+
workflowId: workflowDef.id,
|
|
6239
|
+
status: "running",
|
|
6240
|
+
input,
|
|
6241
|
+
nodeStates: {},
|
|
6242
|
+
currentNodes: [],
|
|
6243
|
+
context: {
|
|
6244
|
+
input
|
|
6245
|
+
// Subworkflow starts with fresh context scoped to its input
|
|
6246
|
+
// We do NOT inherit parent context to ensure isolation,
|
|
6247
|
+
// unless explicitly passed via input.
|
|
6248
|
+
},
|
|
6249
|
+
checkpoints: [],
|
|
6250
|
+
pendingApprovals: [],
|
|
6251
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
6252
|
+
});
|
|
6253
|
+
let finalOutput = result.context;
|
|
6254
|
+
if (result.completed && config.output) {
|
|
6255
|
+
finalOutput = config.output(result.context);
|
|
6256
|
+
}
|
|
6257
|
+
const state = {
|
|
6258
|
+
nodeId: node.id,
|
|
6259
|
+
status: result.completed ? "completed" : result.waiting ? "running" : "failed",
|
|
6260
|
+
output: finalOutput,
|
|
6261
|
+
error: result.error,
|
|
6262
|
+
attempt: 1,
|
|
6263
|
+
startedAt: new Date(startTime),
|
|
6264
|
+
completedAt: result.completed ? /* @__PURE__ */ new Date() : void 0
|
|
6265
|
+
};
|
|
6266
|
+
this.config.onNodeComplete?.(node.id, state);
|
|
6267
|
+
return {
|
|
6268
|
+
state,
|
|
6269
|
+
contextUpdates: result.completed ? { [node.id]: finalOutput } : {},
|
|
6270
|
+
waiting: result.waiting
|
|
6271
|
+
};
|
|
6272
|
+
}
|
|
5938
6273
|
/**
|
|
5939
6274
|
* Execute a step node
|
|
5940
6275
|
*/
|
|
@@ -6442,7 +6777,10 @@ var StepExecutor = class {
|
|
|
6442
6777
|
const resolvedTool = typeof tool2 === "string" ? this.getTool(tool2) : tool2;
|
|
6443
6778
|
const result = await resolvedTool.execute(
|
|
6444
6779
|
input,
|
|
6445
|
-
{
|
|
6780
|
+
{
|
|
6781
|
+
agentId: "workflow",
|
|
6782
|
+
blobStorage: this.config.blobStorage
|
|
6783
|
+
}
|
|
6446
6784
|
);
|
|
6447
6785
|
return result;
|
|
6448
6786
|
}
|
|
@@ -6557,7 +6895,10 @@ var WorkflowExecutor = class _WorkflowExecutor {
|
|
|
6557
6895
|
lockDuration: _WorkflowExecutor.DEFAULT_LOCK_DURATION,
|
|
6558
6896
|
...config
|
|
6559
6897
|
};
|
|
6560
|
-
this.stepExecutor = new StepExecutor(
|
|
6898
|
+
this.stepExecutor = new StepExecutor({
|
|
6899
|
+
...this.config.stepExecutor,
|
|
6900
|
+
blobStorage: this.config.blobStorage
|
|
6901
|
+
});
|
|
6561
6902
|
this.checkpointManager = new CheckpointManager({
|
|
6562
6903
|
backend: this.config.backend,
|
|
6563
6904
|
debug: this.config.debug
|
|
@@ -6572,6 +6913,16 @@ var WorkflowExecutor = class _WorkflowExecutor {
|
|
|
6572
6913
|
onWaiting: () => {
|
|
6573
6914
|
}
|
|
6574
6915
|
});
|
|
6916
|
+
if (this.config.blobStorage) {
|
|
6917
|
+
const bs = this.config.blobStorage;
|
|
6918
|
+
this.blobResolver = {
|
|
6919
|
+
getText: (ref) => ref.__kind === "blob" ? bs.getText(ref.id) : Promise.resolve(null),
|
|
6920
|
+
getBytes: (ref) => ref.__kind === "blob" ? bs.getBytes(ref.id) : Promise.resolve(null),
|
|
6921
|
+
getStream: (ref) => ref.__kind === "blob" ? bs.getStream(ref.id) : Promise.resolve(null),
|
|
6922
|
+
stat: (ref) => ref.__kind === "blob" ? bs.stat(ref.id) : Promise.resolve(null),
|
|
6923
|
+
delete: (ref) => ref.__kind === "blob" ? bs.delete(ref.id) : Promise.resolve(void 0)
|
|
6924
|
+
};
|
|
6925
|
+
}
|
|
6575
6926
|
}
|
|
6576
6927
|
static {
|
|
6577
6928
|
/** Default lock duration: 30 seconds */
|
|
@@ -6745,9 +7096,13 @@ var WorkflowExecutor = class _WorkflowExecutor {
|
|
|
6745
7096
|
if (Array.isArray(workflow2.steps)) {
|
|
6746
7097
|
nodes = workflow2.steps;
|
|
6747
7098
|
} else {
|
|
7099
|
+
if (!this.config.blobStorage) {
|
|
7100
|
+
}
|
|
6748
7101
|
const builderContext = {
|
|
6749
7102
|
input: context.input,
|
|
6750
|
-
context
|
|
7103
|
+
context,
|
|
7104
|
+
blobStorage: this.config.blobStorage,
|
|
7105
|
+
blob: this.blobResolver
|
|
6751
7106
|
};
|
|
6752
7107
|
nodes = workflow2.steps(builderContext);
|
|
6753
7108
|
}
|