Added envvar store, resolves values in short-input, long-input, code sub-blocks. Resolves value at execution time

This commit is contained in:
Waleed Latif
2025-02-01 13:15:11 -08:00
parent 78fa6b44d3
commit 4e44594953
10 changed files with 331 additions and 144 deletions
+31 -15
View File
@@ -23,7 +23,8 @@ export class Executor {
constructor(
private workflow: SerializedWorkflow,
// Initial block states can be passed in if you need to resume workflows or pre-populate data.
private initialBlockStates: Record<string, BlockOutput> = {}
private initialBlockStates: Record<string, BlockOutput> = {},
private environmentVariables: Record<string, string> = {}
) {}
/**
@@ -40,6 +41,7 @@ export class Executor {
metadata: {
startTime: startTime.toISOString()
},
environmentVariables: this.environmentVariables
}
// Pre-populate block states if initialBlockStates exist
@@ -314,10 +316,12 @@ export class Executor {
const resolvedInputs = Object.entries(inputs).reduce(
(acc, [key, value]) => {
if (typeof value === 'string') {
const matches = value.match(/<([^>]+)>/g)
if (matches) {
let resolvedValue = value
for (const match of matches) {
let resolvedValue = value
// Handle block references with <> syntax
const blockMatches = value.match(/<([^>]+)>/g)
if (blockMatches) {
for (const match of blockMatches) {
// e.g. "<someBlockId.response>"
const path = match.slice(1, -1) // remove < and >
const [blockRef, ...pathParts] = path.split('.')
@@ -365,20 +369,32 @@ export class Executor {
throw new Error(`No value found at path "${path}" in block "${sourceBlock.metadata?.title}".`)
}
}
}
// Attempt JSON parse if it looks like JSON
try {
if (resolvedValue.startsWith('{') || resolvedValue.startsWith('[')) {
acc[key] = JSON.parse(resolvedValue)
} else {
acc[key] = resolvedValue
// Handle environment variables with {} syntax
const envMatches = resolvedValue.match(/\{([^}]+)\}/g)
if (envMatches) {
for (const match of envMatches) {
const envKey = match.slice(1, -1) // remove { and }
const envValue = context.environmentVariables?.[envKey]
if (envValue === undefined) {
throw new Error(`Environment variable "${envKey}" was not found.`)
}
} catch {
resolvedValue = resolvedValue.replace(match, envValue)
}
}
// After all replacements are done, attempt JSON parse if it looks like JSON
try {
if (resolvedValue.startsWith('{') || resolvedValue.startsWith('[')) {
acc[key] = JSON.parse(resolvedValue)
} else {
acc[key] = resolvedValue
}
} else {
// No placeholders
acc[key] = value
} catch {
acc[key] = resolvedValue
}
} else {
// Not a string param
+11 -13
View File
@@ -6,31 +6,30 @@ import { BlockOutput } from '@/blocks/types'
export interface BlockLog {
blockId: string
blockTitle?: string
success: boolean
error?: string
blockType?: string
startedAt: string
endedAt: string
durationMs: number
success: boolean
output?: any
blockType?: string
error?: string
}
/**
* Describes the runtime context for executing a workflow,
* including all block outputs (blockStates), metadata for timing, and block logs.
*/
export interface ExecutionMetadata {
startTime?: string
endTime?: string
}
export interface ExecutionContext {
workflowId: string
blockStates: Map<string, BlockOutput>
// Make metadata non-optional so we can assign .startTime or .endTime without TS warnings
metadata: {
startTime?: string
endTime?: string
// You can keep an index signature if you want to store extra fields
[key: string]: any
}
// We store logs in an array so the final result includes a step-by-step record
blockLogs: BlockLog[]
metadata: ExecutionMetadata
environmentVariables?: Record<string, string>
}
/**
@@ -41,13 +40,12 @@ export interface ExecutionResult {
success: boolean
output: BlockOutput
error?: string
logs?: BlockLog[]
metadata?: {
duration: number
startTime: string
endTime: string
}
// Detailed logs of what happened in each block
logs?: BlockLog[]
}
/**