diff --git a/backend/workflow_executor.py b/backend/workflow_executor.py index cdadb4a..eee6080 100644 --- a/backend/workflow_executor.py +++ b/backend/workflow_executor.py @@ -603,22 +603,56 @@ def execute_end_node( "status": node_state.status.value if node_state.status else "unknown", } - # Add normalized signals as {{node_id.signal_X}} - if node_state.normalized_signals: - for signal in node_state.normalized_signals: - # Convert NormalizedSignal object to dict if needed - signal_dict = signal.model_dump() if hasattr(signal, 'model_dump') else signal - signal_key = f"signal_{signal_dict['question_type']}" - node_context[signal_key] = signal_dict['normalized_value'] or signal_dict['raw_value'] - - # Add question texts as {{node_id.question_X}} + # Build question_type β†’ question_id mapping from workflow graph + question_id_map = {} if graph: workflow_node = next((n for n in graph.nodes if n.id == node_id), None) if workflow_node and workflow_node.question_augmentations: for q in workflow_node.question_augmentations: q_dict = q.model_dump() if hasattr(q, 'model_dump') else q - question_key = f"question_{q_dict['type']}" - node_context[question_key] = q_dict.get('question', '') + q_type = q_dict.get('type') + q_id = q_dict.get('id') + if q_type and q_id: + # Multiple questions with same type β†’ use ID + if q_type not in question_id_map: + question_id_map[q_type] = [] + question_id_map[q_type].append(q_id) + + # Add normalized signals as {{node_id.signal_ID}} (not type!) + if node_state.normalized_signals: + # Track which types we've seen (for duplicate detection) + type_counts = {} + + for signal in node_state.normalized_signals: + # Convert NormalizedSignal object to dict if needed + signal_dict = signal.model_dump() if hasattr(signal, 'model_dump') else signal + q_type = signal_dict['question_type'] + + # Determine which ID to use for this signal + if q_type in question_id_map: + # Get the Nth ID for this type (handles duplicates) + type_idx = type_counts.get(q_type, 0) + type_counts[q_type] = type_idx + 1 + + if type_idx < len(question_id_map[q_type]): + q_id = question_id_map[q_type][type_idx] + signal_key = f"signal_{q_id}" + node_context[signal_key] = signal_dict['normalized_value'] or signal_dict['raw_value'] + else: + logger.warning(f"No question_id found for signal type={q_type} index={type_idx}") + else: + logger.warning(f"No question_id mapping for type={q_type}") + + # Add question texts as {{node_id.question_ID}} + if graph: + workflow_node = next((n for n in graph.nodes if n.id == node_id), None) + if workflow_node and workflow_node.question_augmentations: + for q in workflow_node.question_augmentations: + q_dict = q.model_dump() if hasattr(q, 'model_dump') else q + q_id = q_dict.get('id') + if q_id: + question_key = f"question_{q_id}" + node_context[question_key] = q_dict.get('question', '') template_context[node_id] = node_context diff --git a/frontend/src/components/workflow/panels/PlaceholderPicker.jsx b/frontend/src/components/workflow/panels/PlaceholderPicker.jsx index d40e983..6d2381f 100644 --- a/frontend/src/components/workflow/panels/PlaceholderPicker.jsx +++ b/frontend/src/components/workflow/panels/PlaceholderPicker.jsx @@ -376,21 +376,21 @@ function extractWorkflowPlaceholders(nodes) { if (node.type === 'analysis' && node.data.questions && node.data.questions.length > 0) { node.data.questions.forEach((q, qIdx) => { const questionId = q.id || `q${qIdx + 1}` - const questionType = q.type || `q${qIdx + 1}` + const questionType = q.type || 'unknown' const questionText = q.question || `Frage ${qIdx + 1}` - // Signal-Platzhalter (Antwort) + // Signal-Platzhalter (Antwort) - VERWENDET ID fΓΌr Eindeutigkeit! placeholders.push({ - placeholder: `{{ ${nodeId}.signal_${questionType} }}`, - description: `${nodeLabel} (${questionId}) - Signal ${questionType}: ${questionText.substring(0, 40)}${questionText.length > 40 ? '...' : ''}`, + placeholder: `{{ ${nodeId}.signal_${questionId} }}`, + description: `${nodeLabel} - ${questionId} (${questionType}): ${questionText.substring(0, 45)}${questionText.length > 45 ? '...' : ''}`, icon: 'πŸ“Š', category: 'Workflow - Signals' }) // Frage-Text-Platzhalter placeholders.push({ - placeholder: `{{ ${nodeId}.question_${questionType} }}`, - description: `${nodeLabel} (${questionId}) - Frage ${questionType}: ${questionText.substring(0, 40)}${questionText.length > 40 ? '...' : ''}`, + placeholder: `{{ ${nodeId}.question_${questionId} }}`, + description: `${nodeLabel} - ${questionId} (${questionType}): ${questionText.substring(0, 45)}${questionText.length > 45 ? '...' : ''}`, icon: '❓', category: 'Workflow - Questions' })