@relayplane/sdk
Version:
RelayPlane SDK - Local-first AI workflow engine for building multi-step AI workflows
1,325 lines (1,308 loc) • 190 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var crypto$1 = require('crypto');
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
if (typeof require !== "undefined") return require.apply(this, arguments);
throw Error('Dynamic require of "' + x + '" is not supported');
});
var __commonJS = (cb, mod) => function __require2() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
!mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
// ../engine/dist/types/errors.js
var require_errors = __commonJS({
"../engine/dist/types/errors.js"(exports$1) {
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.TemplateError = exports$1.TimeoutError = exports$1.ProviderError = exports$1.StepExecutionError = exports$1.WorkflowDependencyError = exports$1.WorkflowDefinitionError = exports$1.WorkflowError = void 0;
exports$1.isWorkflowError = isWorkflowError;
exports$1.isWorkflowDefinitionError = isWorkflowDefinitionError;
exports$1.isStepExecutionError = isStepExecutionError;
exports$1.isProviderError = isProviderError;
exports$1.isTimeoutError = isTimeoutError;
var WorkflowError = class _WorkflowError extends Error {
cause;
/**
* Creates a new WorkflowError.
*
* @param message - Human-readable error message
* @param cause - Optional underlying error that caused this error
*/
constructor(message, cause) {
super(message);
this.cause = cause;
this.name = "WorkflowError";
Object.setPrototypeOf(this, _WorkflowError.prototype);
}
};
exports$1.WorkflowError = WorkflowError;
var WorkflowDefinitionError = class _WorkflowDefinitionError extends WorkflowError {
constructor(message, cause) {
super(message, cause);
this.name = "WorkflowDefinitionError";
Object.setPrototypeOf(this, _WorkflowDefinitionError.prototype);
}
};
exports$1.WorkflowDefinitionError = WorkflowDefinitionError;
var WorkflowDependencyError = class _WorkflowDependencyError extends WorkflowDefinitionError {
constructor(message, cause) {
super(message, cause);
this.name = "WorkflowDependencyError";
Object.setPrototypeOf(this, _WorkflowDependencyError.prototype);
}
};
exports$1.WorkflowDependencyError = WorkflowDependencyError;
var StepExecutionError = class _StepExecutionError extends WorkflowError {
stepName;
workflowName;
attempts;
/**
* Creates a new StepExecutionError.
*
* @param stepName - Name of the step that failed
* @param workflowName - Name of the workflow being executed
* @param message - Human-readable error message
* @param attempts - Number of execution attempts made
* @param cause - Optional underlying error
*/
constructor(stepName, workflowName, message, attempts = 1, cause) {
super(message, cause);
this.stepName = stepName;
this.workflowName = workflowName;
this.attempts = attempts;
this.name = "StepExecutionError";
Object.setPrototypeOf(this, _StepExecutionError.prototype);
}
};
exports$1.StepExecutionError = StepExecutionError;
var ProviderError = class _ProviderError extends WorkflowError {
provider;
/**
* Creates a new ProviderError.
*
* @param provider - Name of the provider (e.g., "openai", "anthropic")
* @param message - Human-readable error message
* @param cause - Optional underlying provider error
*/
constructor(provider, message, cause) {
super(message, cause);
this.provider = provider;
this.name = "ProviderError";
Object.setPrototypeOf(this, _ProviderError.prototype);
}
};
exports$1.ProviderError = ProviderError;
var TimeoutError = class _TimeoutError extends WorkflowError {
timeoutMs;
/**
* Creates a new TimeoutError.
*
* @param message - Human-readable error message
* @param timeoutMs - The timeout value that was exceeded
* @param cause - Optional underlying error
*/
constructor(message, timeoutMs, cause) {
super(message, cause);
this.timeoutMs = timeoutMs;
this.name = "TimeoutError";
Object.setPrototypeOf(this, _TimeoutError.prototype);
}
};
exports$1.TimeoutError = TimeoutError;
var TemplateError = class _TemplateError extends WorkflowError {
template;
/**
* Creates a new TemplateError.
*
* @param message - Human-readable error message
* @param template - The template string that failed
* @param cause - Optional underlying error
*/
constructor(message, template, cause) {
super(message, cause);
this.template = template;
this.name = "TemplateError";
Object.setPrototypeOf(this, _TemplateError.prototype);
}
};
exports$1.TemplateError = TemplateError;
function isWorkflowError(error) {
return error instanceof WorkflowError;
}
function isWorkflowDefinitionError(error) {
return error instanceof WorkflowDefinitionError;
}
function isStepExecutionError(error) {
return error instanceof StepExecutionError;
}
function isProviderError(error) {
return error instanceof ProviderError;
}
function isTimeoutError(error) {
return error instanceof TimeoutError;
}
}
});
// ../engine/dist/types/index.js
var require_types = __commonJS({
"../engine/dist/types/index.js"(exports$1) {
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.isTimeoutError = exports$1.isProviderError = exports$1.isStepExecutionError = exports$1.isWorkflowDefinitionError = exports$1.isWorkflowError = exports$1.TemplateError = exports$1.TimeoutError = exports$1.ProviderError = exports$1.StepExecutionError = exports$1.WorkflowDependencyError = exports$1.WorkflowDefinitionError = exports$1.WorkflowError = void 0;
var errors_1 = require_errors();
Object.defineProperty(exports$1, "WorkflowError", { enumerable: true, get: function() {
return errors_1.WorkflowError;
} });
Object.defineProperty(exports$1, "WorkflowDefinitionError", { enumerable: true, get: function() {
return errors_1.WorkflowDefinitionError;
} });
Object.defineProperty(exports$1, "WorkflowDependencyError", { enumerable: true, get: function() {
return errors_1.WorkflowDependencyError;
} });
Object.defineProperty(exports$1, "StepExecutionError", { enumerable: true, get: function() {
return errors_1.StepExecutionError;
} });
Object.defineProperty(exports$1, "ProviderError", { enumerable: true, get: function() {
return errors_1.ProviderError;
} });
Object.defineProperty(exports$1, "TimeoutError", { enumerable: true, get: function() {
return errors_1.TimeoutError;
} });
Object.defineProperty(exports$1, "TemplateError", { enumerable: true, get: function() {
return errors_1.TemplateError;
} });
Object.defineProperty(exports$1, "isWorkflowError", { enumerable: true, get: function() {
return errors_1.isWorkflowError;
} });
Object.defineProperty(exports$1, "isWorkflowDefinitionError", { enumerable: true, get: function() {
return errors_1.isWorkflowDefinitionError;
} });
Object.defineProperty(exports$1, "isStepExecutionError", { enumerable: true, get: function() {
return errors_1.isStepExecutionError;
} });
Object.defineProperty(exports$1, "isProviderError", { enumerable: true, get: function() {
return errors_1.isProviderError;
} });
Object.defineProperty(exports$1, "isTimeoutError", { enumerable: true, get: function() {
return errors_1.isTimeoutError;
} });
}
});
// ../engine/dist/validation/dag.js
var require_dag = __commonJS({
"../engine/dist/validation/dag.js"(exports$1) {
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.validateAndSort = validateAndSort;
exports$1.topologicalSort = topologicalSort;
exports$1.detectCycles = detectCycles;
var errors_1 = require_errors();
function validateAndSort(workflow) {
if (!workflow.workflowName || workflow.workflowName.trim() === "") {
throw new errors_1.WorkflowDefinitionError("Workflow name must be a non-empty string");
}
if (!Array.isArray(workflow.steps) || workflow.steps.length === 0) {
throw new errors_1.WorkflowDefinitionError("Workflow must have at least one step");
}
validateUniqueStepNames(workflow.steps);
validateDependencies(workflow.steps);
return topologicalSort(workflow.steps);
}
function validateUniqueStepNames(steps) {
const stepNames = /* @__PURE__ */ new Set();
const duplicates = [];
for (const step of steps) {
if (!step.stepName || step.stepName.trim() === "") {
throw new errors_1.WorkflowDefinitionError("All steps must have a non-empty stepName");
}
if (stepNames.has(step.stepName)) {
duplicates.push(step.stepName);
} else {
stepNames.add(step.stepName);
}
}
if (duplicates.length > 0) {
throw new errors_1.WorkflowDefinitionError(`Duplicate step names found: ${duplicates.join(", ")}`);
}
}
function validateDependencies(steps) {
const stepNames = new Set(steps.map((s) => s.stepName));
for (const step of steps) {
if (!step.model || step.model.trim() === "") {
throw new errors_1.WorkflowDefinitionError(`Step "${step.stepName}" is missing required field "model"`);
}
if (step.dependsOn && step.dependsOn.length > 0) {
for (const dependency of step.dependsOn) {
if (dependency === step.stepName) {
throw new errors_1.WorkflowDefinitionError(`Step "${step.stepName}" cannot depend on itself`);
}
if (!stepNames.has(dependency)) {
throw new errors_1.WorkflowDefinitionError(`Step "${step.stepName}" depends on unknown step "${dependency}"`);
}
}
}
}
}
function topologicalSort(steps) {
const stepMap = /* @__PURE__ */ new Map();
const inDegree = /* @__PURE__ */ new Map();
const dependents = /* @__PURE__ */ new Map();
for (const step of steps) {
stepMap.set(step.stepName, step);
inDegree.set(step.stepName, 0);
dependents.set(step.stepName, /* @__PURE__ */ new Set());
}
for (const step of steps) {
if (step.dependsOn && step.dependsOn.length > 0) {
inDegree.set(step.stepName, step.dependsOn.length);
for (const dependency of step.dependsOn) {
const depSet = dependents.get(dependency);
if (depSet) {
depSet.add(step.stepName);
}
}
}
}
const queue = [];
for (const [stepName, degree] of inDegree.entries()) {
if (degree === 0) {
queue.push(stepName);
}
}
const sorted = [];
const visited = /* @__PURE__ */ new Set();
while (queue.length > 0) {
const currentName = queue.shift();
const currentStep = stepMap.get(currentName);
sorted.push(currentStep);
visited.add(currentName);
const deps = dependents.get(currentName);
if (deps) {
for (const dependentName of deps) {
const degree = inDegree.get(dependentName) - 1;
inDegree.set(dependentName, degree);
if (degree === 0) {
queue.push(dependentName);
}
}
}
}
if (sorted.length !== steps.length) {
const unvisited = steps.filter((s) => !visited.has(s.stepName)).map((s) => s.stepName);
const cycle = findCycle(steps, unvisited);
throw new errors_1.WorkflowDependencyError(`Circular dependency detected: ${cycle.join(" \u2192 ")}`);
}
return sorted;
}
function findCycle(steps, unvisited) {
const stepMap = new Map(steps.map((s) => [s.stepName, s]));
const visiting = /* @__PURE__ */ new Set();
const visited = /* @__PURE__ */ new Set();
const path2 = [];
function dfs(stepName) {
if (visiting.has(stepName)) {
return true;
}
if (visited.has(stepName)) {
return false;
}
visiting.add(stepName);
path2.push(stepName);
const step = stepMap.get(stepName);
if (step?.dependsOn) {
for (const dep of step.dependsOn) {
if (dfs(dep)) {
return true;
}
}
}
visiting.delete(stepName);
visited.add(stepName);
path2.pop();
return false;
}
for (const startNode of unvisited) {
if (dfs(startNode)) {
return [...path2, startNode];
}
}
return unvisited;
}
function detectCycles(steps) {
try {
topologicalSort(steps);
return false;
} catch (error) {
if (error instanceof errors_1.WorkflowDependencyError) {
return true;
}
throw error;
}
}
}
});
// ../engine/dist/utils/uuid.js
var require_uuid = __commonJS({
"../engine/dist/utils/uuid.js"(exports$1) {
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.generateUUID = generateUUID;
exports$1.generateRunId = generateRunId;
function generateUUID() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
const r = Math.random() * 16 | 0;
const v = c === "x" ? r : r & 3 | 8;
return v.toString(16);
});
}
function generateRunId(prefix = "run") {
return `${prefix}_${generateUUID()}`;
}
}
});
// ../engine/dist/execution/context.js
var require_context = __commonJS({
"../engine/dist/execution/context.js"(exports$1) {
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.ExecutionContextImpl = void 0;
var uuid_1 = require_uuid();
var ExecutionContextImpl = class {
runId;
workflowName;
startTime;
endTime;
initialInput;
stepOutputs;
logs;
options;
finalized = false;
/**
* Creates a new execution context for a workflow run.
*
* @param workflow - The workflow being executed
* @param initialInput - Input provided by the user
* @param options - Runtime options for this execution
* @param runId - Optional custom run ID (generated if not provided)
*/
constructor(workflow, initialInput, options = {}, runId) {
this.runId = runId || (0, uuid_1.generateRunId)();
this.workflowName = workflow.workflowName;
this.startTime = (/* @__PURE__ */ new Date()).toISOString();
this.initialInput = initialInput;
this.stepOutputs = /* @__PURE__ */ new Map();
this.logs = [];
this.options = options;
}
/**
* Stores the output of a completed step.
*
* @param stepName - Name of the step
* @param output - Output value from the step
* @throws {Error} If context is already finalized
*/
setOutput(stepName, output) {
if (this.finalized) {
throw new Error("Cannot set output on finalized context");
}
this.stepOutputs.set(stepName, output);
}
/**
* Retrieves the output of a previously executed step.
*
* @param stepName - Name of the step
* @returns Output value, or undefined if step hasn't executed
*/
getOutput(stepName) {
return this.stepOutputs.get(stepName);
}
/**
* Checks if a step has been executed and has output.
*
* @param stepName - Name of the step
* @returns True if step has output stored
*/
hasOutput(stepName) {
return this.stepOutputs.has(stepName);
}
/**
* Appends a step execution log to the context.
*
* @param log - Step execution log entry
* @throws {Error} If context is already finalized
*/
appendLog(log) {
if (this.finalized) {
throw new Error("Cannot append log to finalized context");
}
this.logs.push(log);
}
/**
* Gets all execution logs in order.
*
* @returns Array of step execution logs
*/
getLogs() {
return [...this.logs];
}
/**
* Gets the number of steps that have been executed.
*
* @returns Number of logs
*/
getStepCount() {
return this.logs.length;
}
/**
* Finalizes the context by setting the end time.
*
* After finalization, no more outputs or logs can be added.
*/
finalize() {
if (!this.finalized) {
this.endTime = (/* @__PURE__ */ new Date()).toISOString();
this.finalized = true;
}
}
/**
* Checks if the context has been finalized.
*
* @returns True if finalized
*/
isFinalized() {
return this.finalized;
}
/**
* Gets the total duration of the workflow run in milliseconds.
*
* @returns Duration in ms, or undefined if not finalized
*/
getDuration() {
if (!this.endTime) {
return void 0;
}
return new Date(this.endTime).getTime() - new Date(this.startTime).getTime();
}
/**
* Creates a summary object of the execution context.
*
* @returns Summary object with key metrics
*/
getSummary() {
return {
runId: this.runId,
workflowName: this.workflowName,
startTime: this.startTime,
endTime: this.endTime,
duration: this.getDuration(),
stepCount: this.logs.length,
outputCount: this.stepOutputs.size,
finalized: this.finalized
};
}
};
exports$1.ExecutionContextImpl = ExecutionContextImpl;
}
});
// ../engine/dist/utils/interpolate.js
var require_interpolate = __commonJS({
"../engine/dist/utils/interpolate.js"(exports$1) {
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.interpolate = interpolate;
exports$1.hasTemplateVariables = hasTemplateVariables;
exports$1.interpolateValue = interpolateValue;
var errors_1 = require_errors();
function interpolate(template, context) {
if (typeof template !== "string") {
return template;
}
const pattern = /\{\{([^}]+)\}\}/g;
let result = template;
const matches = Array.from(template.matchAll(pattern));
for (const match of matches) {
const fullMatch = match[0];
const expression = match[1].trim();
try {
const value = resolveExpression(expression, context);
const replacement = formatValue(value);
result = result.replace(fullMatch, replacement);
} catch (error) {
if (error instanceof errors_1.TemplateError) {
throw error;
}
throw new errors_1.TemplateError(`Failed to resolve template variable "${fullMatch}": ${error instanceof Error ? error.message : String(error)}`, fullMatch);
}
}
return result;
}
function resolveExpression(expression, context) {
const parts = expression.split(".");
if (parts.length < 2) {
throw new errors_1.TemplateError(`Invalid template expression "${expression}". Expected format: "stepName.output[.field]"`, `{{${expression}}}`);
}
const stepName = parts[0];
const accessor = parts[1];
if (!context.has(stepName)) {
throw new errors_1.TemplateError(`Cannot resolve template variable "{{${expression}}}": step "${stepName}" not found or has not executed yet`, `{{${expression}}}`);
}
let value = context.get(stepName);
let startIndex = 2;
if (stepName === "input") {
startIndex = 1;
} else {
if (accessor !== "output") {
throw new errors_1.TemplateError(`Invalid template expression "${expression}". Second part must be "output"`, `{{${expression}}}`);
}
}
for (let i = startIndex; i < parts.length; i++) {
const prop = parts[i];
if (value === null || value === void 0) {
throw new errors_1.TemplateError(`Cannot access property "${prop}" in "{{${expression}}}": parent value is ${value}`, `{{${expression}}}`);
}
if (typeof value !== "object") {
throw new errors_1.TemplateError(`Cannot access property "${prop}" in "{{${expression}}}": parent is not an object`, `{{${expression}}}`);
}
if (!(prop in value)) {
throw new errors_1.TemplateError(`Cannot access property "${prop}" in "{{${expression}}}": property does not exist`, `{{${expression}}}`);
}
value = value[prop];
}
return value;
}
function formatValue(value) {
if (value === null || value === void 0) {
return "";
}
if (typeof value === "string") {
return value;
}
if (typeof value === "number" || typeof value === "boolean") {
return String(value);
}
if (typeof value === "object") {
return JSON.stringify(value);
}
return String(value);
}
function hasTemplateVariables(str) {
if (typeof str !== "string") {
return false;
}
return /\{\{[^}]+\}\}/.test(str);
}
function interpolateValue(value, context) {
if (typeof value === "string") {
return interpolate(value, context);
}
if (Array.isArray(value)) {
return value.map((item) => interpolateValue(item, context));
}
if (value !== null && typeof value === "object") {
const result = {};
for (const [key, val] of Object.entries(value)) {
result[key] = interpolateValue(val, context);
}
return result;
}
return value;
}
}
});
// ../engine/dist/execution/input-resolver.js
var require_input_resolver = __commonJS({
"../engine/dist/execution/input-resolver.js"(exports$1) {
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.resolveStepInput = resolveStepInput;
exports$1.areDependenciesReady = areDependenciesReady;
var interpolate_1 = require_interpolate();
function resolveStepInput(step, context) {
const interpolationContext = /* @__PURE__ */ new Map();
if (context.initialInput !== void 0 && context.initialInput !== null) {
interpolationContext.set("input", context.initialInput);
}
for (const [stepName, output] of context.stepOutputs.entries()) {
interpolationContext.set(stepName, output);
}
let baseInput;
if (step.input !== void 0) {
baseInput = step.input;
} else if (step.prompt !== void 0) {
baseInput = step.prompt;
} else {
baseInput = context.initialInput;
}
const resolvedInput = (0, interpolate_1.interpolateValue)(baseInput, interpolationContext);
if (step.dependsOn && step.dependsOn.length > 0) {
const dependencies = {};
for (const depName of step.dependsOn) {
const depOutput = context.getOutput(depName);
if (depOutput !== void 0) {
dependencies[depName] = depOutput;
}
}
return {
input: resolvedInput,
dependencies
};
}
return resolvedInput;
}
function areDependenciesReady(step, context) {
if (!step.dependsOn || step.dependsOn.length === 0) {
return true;
}
return step.dependsOn.every((depName) => context.hasOutput(depName));
}
}
});
// ../engine/dist/execution/retry.js
var require_retry = __commonJS({
"../engine/dist/execution/retry.js"(exports$1) {
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.calculateBackoff = calculateBackoff;
exports$1.sleep = sleep;
exports$1.isRecoverableError = isRecoverableError;
function calculateBackoff(attempt, baseDelay = 1e3, jitterFactor = 0.2) {
const exponentialDelay = baseDelay * Math.pow(2, attempt);
const jitter = 1 + (Math.random() * 2 - 1) * jitterFactor;
return Math.floor(exponentialDelay * jitter);
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
function isRecoverableError(error) {
if (!error) {
return false;
}
const errorType = error.type || error.error?.type;
if (errorType === "RateLimitError" || errorType === "rate_limit_exceeded") {
return true;
}
if (errorType === "TimeoutError" || errorType === "timeout") {
return true;
}
if (errorType === "NetworkError" || errorType === "ECONNRESET" || errorType === "ETIMEDOUT") {
return true;
}
if (error.statusCode >= 500 && error.statusCode < 600) {
return true;
}
const message = (error.message || "").toLowerCase();
if (message.includes("timeout") || message.includes("rate limit") || message.includes("503")) {
return true;
}
return false;
}
}
});
// ../engine/dist/execution/executor.js
var require_executor = __commonJS({
"../engine/dist/execution/executor.js"(exports$1) {
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.executeStep = executeStep;
exports$1.validateStepExecution = validateStepExecution;
var errors_1 = require_errors();
var input_resolver_1 = require_input_resolver();
var retry_1 = require_retry();
var DEFAULT_STEP_TIMEOUT = 12e4;
function createTimeout(ms, stepName) {
return new Promise((_, reject) => {
setTimeout(() => {
reject(new errors_1.TimeoutError(`Step "${stepName}" timed out after ${ms}ms`, ms));
}, ms);
});
}
async function executeStep(step, context, adapterExecutor) {
const startTime = Date.now();
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
const maxRetries = step.retry?.maxRetries ?? 0;
const baseBackoff = step.retry?.backoffMs ?? 1e3;
const timeout = step.timeout ?? DEFAULT_STEP_TIMEOUT;
let lastError;
let attempts = 0;
while (attempts <= maxRetries) {
attempts++;
try {
const resolvedInput = (0, input_resolver_1.resolveStepInput)(step, context);
const adapterPromise = adapterExecutor({
model: step.model,
input: resolvedInput,
schema: step.schema,
stepName: step.stepName,
workflowName: context.workflowName,
stepMetadata: step.metadata
});
const result = await Promise.race([
adapterPromise,
createTimeout(timeout, step.stepName)
]);
if (result.success) {
const finishedAt2 = (/* @__PURE__ */ new Date()).toISOString();
const durationMs2 = Date.now() - startTime;
return {
stepName: step.stepName,
model: step.model,
startedAt,
finishedAt: finishedAt2,
durationMs: durationMs2,
success: true,
output: result.output,
attempts,
tokensIn: result.tokensIn,
tokensOut: result.tokensOut
};
}
lastError = result.error;
if (!(0, retry_1.isRecoverableError)(lastError) || attempts > maxRetries) {
break;
}
const delay = (0, retry_1.calculateBackoff)(attempts - 1, baseBackoff);
await (0, retry_1.sleep)(delay);
} catch (error) {
if (error instanceof errors_1.TimeoutError) {
lastError = {
type: "TimeoutError",
message: error.message,
timeoutMs: error.timeoutMs
};
break;
}
lastError = {
type: "UnexpectedError",
message: error instanceof Error ? error.message : String(error),
raw: error
};
if (!(0, retry_1.isRecoverableError)(error) || attempts > maxRetries) {
break;
}
const delay = (0, retry_1.calculateBackoff)(attempts - 1, baseBackoff);
await (0, retry_1.sleep)(delay);
}
}
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
const durationMs = Date.now() - startTime;
return {
stepName: step.stepName,
model: step.model,
startedAt,
finishedAt,
durationMs,
success: false,
error: lastError || {
type: "UnknownError",
message: "Step failed with unknown error"
},
attempts
};
}
function validateStepExecution(step, context) {
if (!step.stepName || !step.model) {
throw new errors_1.StepExecutionError(step.stepName || "unknown", context.workflowName, "Step is missing required fields (stepName or model)", 0);
}
if (step.dependsOn && step.dependsOn.length > 0) {
for (const depName of step.dependsOn) {
if (!context.hasOutput(depName)) {
throw new errors_1.StepExecutionError(step.stepName, context.workflowName, `Step "${step.stepName}" depends on "${depName}" which has not been executed`, 0);
}
}
}
}
}
});
// ../engine/dist/execution/condition-evaluator.js
var require_condition_evaluator = __commonJS({
"../engine/dist/execution/condition-evaluator.js"(exports$1) {
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.evaluateCondition = evaluateCondition;
exports$1.validateCondition = validateCondition;
function evaluateCondition(condition, context) {
const conditionContext = buildConditionContext(context);
try {
const evaluator = new Function("input", "steps", `"use strict"; return (${condition});`);
const result = evaluator(conditionContext.input, conditionContext.steps);
return {
shouldExecute: Boolean(result)
};
} catch (error) {
return {
shouldExecute: false,
error: `Condition evaluation failed: ${error instanceof Error ? error.message : String(error)}`
};
}
}
function buildConditionContext(context) {
const steps = {};
for (const [stepName, output] of context.stepOutputs.entries()) {
steps[stepName] = { output };
}
return {
input: context.initialInput,
steps
};
}
function validateCondition(condition) {
try {
new Function("input", "steps", `"use strict"; return (${condition});`);
return true;
} catch (error) {
throw new Error(`Invalid condition expression: ${error instanceof Error ? error.message : String(error)}`);
}
}
}
});
// ../engine/dist/runner/runner.js
var require_runner = __commonJS({
"../engine/dist/runner/runner.js"(exports$1) {
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.WorkflowRunner = void 0;
exports$1.runWorkflow = runWorkflow2;
var dag_1 = require_dag();
var context_1 = require_context();
var executor_1 = require_executor();
var condition_evaluator_1 = require_condition_evaluator();
var WorkflowRunner = class {
/**
* Adapter executor function to use for all steps.
*/
adapterExecutor;
/**
* Creates a new WorkflowRunner instance.
*
* @param adapterExecutor - Function that executes adapter calls
*/
constructor(adapterExecutor) {
this.adapterExecutor = adapterExecutor;
}
/**
* Executes a complete workflow from start to finish.
*
* This method:
* 1. Validates the workflow DAG structure
* 2. Topologically sorts steps based on dependencies
* 3. Initializes execution context
* 4. Executes each step sequentially in dependency order
* 5. Handles step failures (aborts on first failure)
* 6. Aggregates results into a WorkflowRunResult
*
* @param workflow - The workflow definition to execute
* @param initialInput - Initial input to provide to the workflow
* @param options - Optional runtime configuration
* @returns Complete workflow execution result with all step logs
*
* @example
* ```typescript
* const workflow: WorkflowDefinition = {
* workflowName: 'greeting',
* steps: [
* { stepName: 'greet', model: 'gpt-4o', prompt: 'Say hello' }
* ]
* };
*
* const result = await runner.run(workflow, {});
* console.log(result.finalOutput);
* ```
*/
async run(workflow, initialInput, options = {}) {
let sortedSteps;
try {
sortedSteps = (0, dag_1.validateAndSort)(workflow);
} catch (error) {
const runId = this.generateRunId();
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
return {
runId,
workflowName: workflow.workflowName,
startedAt,
finishedAt,
success: false,
steps: []
// Store validation error information
};
}
const context = new context_1.ExecutionContextImpl(workflow, initialInput, options);
const executionLevels = this.groupStepsByLevel(sortedSteps);
let aborted = false;
for (const levelSteps of executionLevels) {
if (aborted)
break;
const stepPromises = [];
for (const step of levelSteps) {
stepPromises.push(this.executeStepWithCondition(step, context));
}
const results = await Promise.all(stepPromises);
for (const { step, log, skipped } of results) {
if (skipped) {
context.appendLog(log);
context.setOutput(step.stepName, void 0);
continue;
}
context.appendLog(log);
if (log.success) {
context.setOutput(step.stepName, log.output);
} else {
aborted = true;
break;
}
}
}
context.finalize();
const result = {
runId: context.runId,
workflowName: context.workflowName,
startedAt: context.startTime,
finishedAt: context.endTime,
success: this.isWorkflowSuccessful(context),
steps: context.logs,
finalOutput: this.getFinalOutput(sortedSteps, context)
};
return result;
}
/**
* Generates a unique run ID.
* Uses a simple timestamp-based approach for the MVP.
*
* @returns Unique run identifier
*/
generateRunId() {
return `run_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
}
/**
* Determines if the workflow executed successfully.
* A workflow is successful if all steps executed and succeeded.
*
* @param context - Execution context
* @returns True if workflow completed successfully
*/
isWorkflowSuccessful(context) {
return context.logs.length > 0 && context.logs.every((log) => log.success);
}
/**
* Gets the final output of the workflow.
* The final output is the output of the last step in execution order.
*
* @param sortedSteps - Steps in topological order
* @param context - Execution context
* @returns Output from the final step, or undefined if no steps or last step failed
*/
getFinalOutput(sortedSteps, context) {
if (sortedSteps.length === 0 || context.logs.length === 0) {
return void 0;
}
const lastLog = context.logs[context.logs.length - 1];
return lastLog.success ? lastLog.output : void 0;
}
/**
* Groups steps by execution level for parallel execution.
* Steps at the same level have no dependencies on each other and can run in parallel.
*
* @param sortedSteps - Topologically sorted steps
* @returns Array of step arrays, where each inner array can be executed in parallel
*/
groupStepsByLevel(sortedSteps) {
if (sortedSteps.length === 0)
return [];
const levels = [];
const stepLevel = /* @__PURE__ */ new Map();
for (const step of sortedSteps) {
let level = 0;
if (step.dependsOn && step.dependsOn.length > 0) {
for (const depName of step.dependsOn) {
const depLevel = stepLevel.get(depName) ?? 0;
level = Math.max(level, depLevel + 1);
}
}
stepLevel.set(step.stepName, level);
while (levels.length <= level) {
levels.push([]);
}
levels[level].push(step);
}
return levels;
}
/**
* Executes a step with condition evaluation.
*
* @param step - Step to execute
* @param context - Execution context
* @returns Execution result with step, log, and skipped flag
*/
async executeStepWithCondition(step, context) {
try {
(0, executor_1.validateStepExecution)(step, context);
} catch (error) {
const log2 = {
stepName: step.stepName,
model: step.model,
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
durationMs: 0,
success: false,
error: {
type: "ValidationError",
message: error instanceof Error ? error.message : String(error)
},
attempts: 0
};
return { step, log: log2, skipped: false };
}
if (step.condition) {
const conditionResult = (0, condition_evaluator_1.evaluateCondition)(step.condition, context);
if (conditionResult.error) {
const log2 = {
stepName: step.stepName,
model: step.model,
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
durationMs: 0,
success: false,
error: {
type: "ConditionError",
message: conditionResult.error
},
attempts: 0
};
return { step, log: log2, skipped: false };
}
if (!conditionResult.shouldExecute) {
const log2 = {
stepName: step.stepName,
model: step.model,
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
durationMs: 0,
success: true,
// Skipped steps are considered successful
output: void 0,
attempts: 0,
skipped: true,
skipReason: `Condition "${step.condition}" evaluated to false`
};
return { step, log: log2, skipped: true };
}
}
const log = await (0, executor_1.executeStep)(step, context, this.adapterExecutor);
return { step, log, skipped: false };
}
};
exports$1.WorkflowRunner = WorkflowRunner;
async function runWorkflow2(workflow, initialInput, adapterExecutor, options) {
const runner = new WorkflowRunner(adapterExecutor);
return runner.run(workflow, initialInput, options);
}
}
});
// ../engine/dist/telemetry/tracer.js
var require_tracer = __commonJS({
"../engine/dist/telemetry/tracer.js"(exports$1) {
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.createSpan = createSpan;
exports$1.endSpan = endSpan;
exports$1.addChildSpan = addChildSpan;
exports$1.setSpanAttribute = setSpanAttribute;
exports$1.generateTraceId = generateTraceId;
exports$1.generateSpanId = generateSpanId;
exports$1.createTraceContext = createTraceContext;
exports$1.formatTraceparent = formatTraceparent;
exports$1.parseTraceparent = parseTraceparent;
exports$1.flattenSpans = flattenSpans;
exports$1.totalDuration = totalDuration;
exports$1.countSpans = countSpans;
function createSpan(name, attributes = {}) {
return {
name,
startTime: (/* @__PURE__ */ new Date()).toISOString(),
status: "ok",
attributes,
children: []
};
}
function endSpan(span, status = "ok", errorMessage) {
span.endTime = (/* @__PURE__ */ new Date()).toISOString();
span.durationMs = new Date(span.endTime).getTime() - new Date(span.startTime).getTime();
span.status = status;
if (errorMessage) {
span.errorMessage = errorMessage;
}
}
function addChildSpan(parent, child) {
parent.children.push(child);
}
function setSpanAttribute(span, key, value) {
span.attributes[key] = value;
}
function generateTraceId() {
const bytes = new Uint8Array(16);
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
crypto.getRandomValues(bytes);
} else {
for (let i = 0; i < 16; i++) {
bytes[i] = Math.floor(Math.random() * 256);
}
}
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
}
function generateSpanId() {
const bytes = new Uint8Array(8);
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
crypto.getRandomValues(bytes);
} else {
for (let i = 0; i < 8; i++) {
bytes[i] = Math.floor(Math.random() * 256);
}
}
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
}
function createTraceContext(parentContext) {
return {
traceId: parentContext?.traceId || generateTraceId(),
spanId: generateSpanId(),
parentSpanId: parentContext?.spanId
};
}
function formatTraceparent(context) {
return `00-${context.traceId}-${context.spanId}-01`;
}
function parseTraceparent(traceparent) {
const parts = traceparent.split("-");
if (parts.length !== 4 || parts[0] !== "00") {
return void 0;
}
const [, traceId, spanId] = parts;
if (traceId.length !== 32 || spanId.length !== 16) {
return void 0;
}
return {
traceId,
spanId,
parentSpanId: spanId
// Use the parsed span as parent
};
}
function flattenSpans(span) {
const result = [span];
for (const child of span.children) {
result.push(...flattenSpans(child));
}
return result;
}
function totalDuration(span) {
return span.durationMs || 0;
}
function countSpans(span) {
let count = 1;
for (const child of span.children) {
count += countSpans(child);
}
return count;
}
}
});
// ../engine/dist/telemetry/index.js
var require_telemetry = __commonJS({
"../engine/dist/telemetry/index.js"(exports$1) {
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.countSpans = exports$1.totalDuration = exports$1.flattenSpans = exports$1.parseTraceparent = exports$1.formatTraceparent = exports$1.createTraceContext = exports$1.generateSpanId = exports$1.generateTraceId = exports$1.setSpanAttribute = exports$1.addChildSpan = exports$1.endSpan = exports$1.createSpan = void 0;
var tracer_1 = require_tracer();
Object.defineProperty(exports$1, "createSpan", { enumerable: true, get: function() {
return tracer_1.createSpan;
} });
Object.defineProperty(exports$1, "endSpan", { enumerable: true, get: function() {
return tracer_1.endSpan;
} });
Object.defineProperty(exports$1, "addChildSpan", { enumerable: true, get: function() {
return tracer_1.addChildSpan;
} });
Object.defineProperty(exports$1, "setSpanAttribute", { enumerable: true, get: function() {
return tracer_1.setSpanAttribute;
} });
Object.defineProperty(exports$1, "generateTraceId", { enumerable: true, get: function() {
return tracer_1.generateTraceId;
} });
Object.defineProperty(exports$1, "generateSpanId", { enumerable: true, get: function() {
return tracer_1.generateSpanId;
} });
Object.defineProperty(exports$1, "createTraceContext", { enumerable: true, get: function() {
return tracer_1.createTraceContext;
} });
Object.defineProperty(exports$1, "formatTraceparent", { enumerable: true, get: function() {
return tracer_1.formatTraceparent;
} });
Object.defineProperty(exports$1, "parseTraceparent", { enumerable: true, get: function() {
return tracer_1.parseTraceparent;
} });
Object.defineProperty(exports$1, "flattenSpans", { enumerable: true, get: function() {
return tracer_1.flattenSpans;
} });
Object.defineProperty(exports$1, "totalDuration", { enumerable: true, get: function() {
return tracer_1.totalDuration;
} });
Object.defineProperty(exports$1, "countSpans", { enumerable: true, get: function() {
return tracer_1.countSpans;
} });
}
});
// ../engine/dist/index.js
var require_dist = __commonJS({
"../engine/dist/index.js"(exports$1) {
var __createBinding = exports$1 && exports$1.__createBinding || (Object.create ? (function(o, m, k, k2) {
if (k2 === void 0) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() {
return m[k];
} };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === void 0) k2 = k;
o[k2] = m[k];
}));
var __exportStar = exports$1 && exports$1.__exportStar || function(m, exports2) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p)) __createBinding(exports2, m, p);
};
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.runWorkflow = exports$1.WorkflowRunner = exports$1.generateRunId = exports$1.generateUUID = exports$1.hasTemplateVariables = exports$1.interpolateValue = exports$1.interpolate = exports$1.validateCondition = exports$1.evaluateCondition = exports$1.isRecoverableError = exports$1.sleep = exports$1.calculateBackoff = exports$1.areDependenciesReady = exports$1.resolveStepInput = exports$1.validateStepExecution = exports$1.executeStep = exports$1.ExecutionContextImpl = exports$1.detectCycles = exports$1.topologicalSort = exports$1.validateAndSort = void 0;
__exportStar(require_types(), exports$1);
var dag_1 = require_dag();
Object.defineProperty(exports$1, "validateAndSort", { enumerable: true, get: function() {
return dag_1.validateAndSort;
} });
Object.defineProperty(exports$1, "topologicalSort", { enumerable: true, get: function() {
return dag_1.topologicalSort;
} });
Object.defineProperty(exports$1, "detectCycles", { enumerable: true, get: function() {
return dag_1.detectCycles;
} });
var context_1 = require_context();
Object.defineProperty(exports$1, "ExecutionContextImpl", { enumerable: true, get: function() {
return context_1.ExecutionContextImpl;
} });
var executor_1 = require_executor();
Object.defineProperty(exports$1, "executeStep", { enumerable: true, get: function() {
return executor_1.executeStep;
} });
Object.defineProperty(exports$1, "validateStepExecution", { enumerable: true, get: function() {
return executor_1.validateStepExecution;
} });
var input_resolver_1 = require_input_resolver();
Object.defineProperty(exports$1, "resolveStepInput", { enumerable: true, get: function() {
return input_resolver_1.resolve