@ -1166,75 +1166,93 @@ export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
break ;
break ;
case "annotation" : {
case "annotation" : {
// Get connected image and set as source (use first image)
try {
const { images } = getConnectedInputs ( node . id ) ;
// Get connected image and set as source (use first image)
const image = images [ 0 ] || null ;
const { images } = getConnectedInputs ( node . id ) ;
if ( image ) {
const image = images [ 0 ] || null ;
updateNodeData ( node . id , { sourceImage : image } ) ;
if ( image ) {
// If no annotations, pass through the image
updateNodeData ( node . id , { sourceImage : image } ) ;
const nodeData = node . data as AnnotationNodeData ;
// If no annotations, pass through the image
if ( ! nodeData . outputImage ) {
const nodeData = node . data as AnnotationNodeData ;
updateNodeData ( node . id , { outputImage : image } ) ;
if ( ! nodeData . outputImage ) {
updateNodeData ( node . id , { outputImage : image } ) ;
}
}
}
} catch ( err ) {
const message = err instanceof Error ? err.message : String ( err ) ;
console . error ( ` [Workflow] Annotation node ${ node . id } failed: ` , message ) ;
updateNodeData ( node . id , { error : message } ) ;
}
}
break ;
break ;
}
}
case "prompt" : {
case "prompt" : {
// Check for connected text input and update prompt if connected
try {
const { text : connectedText } = getConnectedInputs ( node . id ) ;
// Check for connected text input and update prompt if connected
if ( connectedText !== null ) {
const { text : connectedText } = getConnectedInputs ( node . id ) ;
updateNodeData ( node . id , { prompt : connectedText } ) ;
if ( connectedText !== null ) {
updateNodeData ( node . id , { prompt : connectedText } ) ;
}
} catch ( err ) {
const message = err instanceof Error ? err.message : String ( err ) ;
console . error ( ` [Workflow] Prompt node ${ node . id } failed: ` , message ) ;
updateNodeData ( node . id , { error : message } ) ;
}
}
break ;
break ;
}
}
case "promptConstructor" : {
case "promptConstructor" : {
// Get fresh node data from store
try {
const freshNode = get ( ) . nodes . find ( ( n ) = > n . id === node . id ) ;
// Get fresh node data from store
const nodeData = ( freshNode ? . data || node . data ) as PromptConstructorNodeData ;
const freshNode = get ( ) . nodes . find ( ( n ) = > n . id === node . id ) ;
const template = nodeData . template ;
const nodeData = ( freshNode ? . data || node . data ) as PromptConstructorNodeData ;
const template = nodeData . template ;
// Find connected prompt nodes via text edges
const connectedPromptNodes = edges
// Find connected prompt nodes via text edges
. filter ( ( e ) = > e . target === node . id && e . targetHandle === "text" )
const connectedPromptNodes = edges
. map ( ( e ) = > nodes . find ( ( n ) = > n . id === e . source ) )
. filter ( ( e ) = > e . target === node . id && e . targetHandle === "text" )
. filter ( ( n ) : n is WorkflowNode = > n !== undefined && n . type === "prompt" ) ;
. map ( ( e ) = > nodes . find ( ( n ) = > n . id === e . source ) )
. filter ( ( n ) : n is WorkflowNode = > n !== undefined && n . type === "prompt" ) ;
// Build variable map from connected prompt nodes
const variableMap : Record < string , string > = { } ;
// Build variable map from connected prompt nodes
connectedPromptNodes . forEach ( ( promptNode ) = > {
const variableMap : Record < string , string > = { } ;
const promptData = promptNode . data as PromptNodeData ;
connectedPromptNodes . forEach ( ( promptNode ) = > {
if ( promptData . variableName ) {
const promptData = promptNode . data as PromptNodeData ;
variableMap [ promptData . variableName ] = promptData . prompt ;
if ( promptData . variableName ) {
}
variableMap [ promptData . variableName ] = promptData . prompt ;
} ) ;
}
} ) ;
// Find all @variable patterns in template
// Find all @variable patterns in template
const varPattern = /@(\w+)/g ;
const varPattern = /@(\w+)/g ;
const unresolvedVars : string [ ] = [ ] ;
const unresolvedVars : string [ ] = [ ] ;
let resolvedText = template ;
let resolvedText = template ;
// Replace @variables with values or track unresolved
// Replace @variables with values or track unresolved
const matches = template . matchAll ( varPattern ) ;
const matches = template . matchAll ( varPattern ) ;
for ( const match of matches ) {
for ( const match of matches ) {
const varName = match [ 1 ] ;
const varName = match [ 1 ] ;
if ( variableMap [ varName ] !== undefined ) {
if ( variableMap [ varName ] !== undefined ) {
// Replace with actual value
// Replace with actual value
resolvedText = resolvedText . replace ( new RegExp ( ` @ ${ varName } ` , 'g' ) , variableMap [ varName ] ) ;
resolvedText = resolvedText . replaceAll ( ` @ ${ varName } ` , variableMap [ varName ] ) ;
} else {
} else {
// Track unresolved variable
// Track unresolved variable
if ( ! unresolvedVars . includes ( varName ) ) {
if ( ! unresolvedVars . includes ( varName ) ) {
unresolvedVars . push ( varName ) ;
unresolvedVars . push ( varName ) ;
}
}
}
}
}
}
// Update node with resolved text and unresolved vars list
// Update node with resolved text and unresolved vars list
updateNodeData ( node . id , {
updateNodeData ( node . id , {
outputText : resolvedText ,
outputText : resolvedText ,
unresolvedVars ,
unresolvedVars ,
} ) ;
} ) ;
} catch ( err ) {
const message = err instanceof Error ? err.message : String ( err ) ;
console . error ( ` [Workflow] PromptConstructor node ${ node . id } failed: ` , message ) ;
updateNodeData ( node . id , { error : message } ) ;
}
break ;
break ;
}
}