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 CHANGED
@@ -844,17 +844,30 @@ var GoogleProvider = class extends BaseProvider {
844
844
  }
845
845
  };
846
846
 
847
- // src/ai/providers/factory.ts
848
- function getEnv(name) {
849
- if (typeof Deno !== "undefined" && Deno.env) {
850
- return process.env(name);
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
- const _global = globalThis;
853
- if (typeof _global.process !== "undefined" && _global.process.env) {
854
- return _global.process.env[name];
861
+ return process.cwd();
862
+ }
863
+ function getEnv(key) {
864
+ if (isDeno) {
865
+ return process.env(key);
855
866
  }
856
- return void 0;
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.7",
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: async (path) => {
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 (!fs || !path) {
3948
+ const { fs: fs2, path } = await getNodeDeps(context);
3949
+ if (!fs2 || !path) {
3930
3950
  return files;
3931
3951
  }
3932
- if (!fs.existsSync(dir)) {
3952
+ if (!fs2.existsSync(dir)) {
3933
3953
  return files;
3934
3954
  }
3935
- const entries = fs.readdirSync(dir, { withFileTypes: true });
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 = detectCwd(),
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 loadManifest(manifestPath);
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
- console.log(`[setupAI] Loaded manifest: ${tools.size} tools, ${agents.size} agents`);
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
- console.log(`[setupAI] Discovered: ${tools.size} tools, ${agents.size} agents`);
4285
+ cliLogger.info(`[setupAI] Discovered: ${tools.size} tools, ${agents.size} agents`);
4111
4286
  }
4112
4287
  } catch (error) {
4113
4288
  if (verbose) {
4114
- console.log(`[setupAI] Discovery skipped: ${error}`);
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
- throw new Error(
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
- { agentId: "workflow" }
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(this.config.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
  }