From 77f1ed14c539abffaca433b0f3a793181e816c08 Mon Sep 17 00:00:00 2001 From: Lars Date: Sun, 12 Apr 2026 12:29:52 +0200 Subject: [PATCH 1/4] fix: Cursor-Problem beim Frage-ID Editieren MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Cursor springt nach jedem Tastendruck aus dem ID-Feld Ursache: key={q.id} in QuestionEditor map - Wenn ID geändert wird, ändert sich der React Key - React unmountet alte Component und mountet neue - Focus geht verloren Lösung: key={idx} verwenden - Stabiler Key während Editing - Komponente bleibt gemountet - Cursor bleibt im Feld UX: Jetzt kann man IDs flüssig editieren ohne Unterbrechung Co-Authored-By: Claude Opus 4.6 --- .../components/workflow/panels/QuestionAugmentationPanel.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/workflow/panels/QuestionAugmentationPanel.jsx b/frontend/src/components/workflow/panels/QuestionAugmentationPanel.jsx index 2def832..a2f4d44 100644 --- a/frontend/src/components/workflow/panels/QuestionAugmentationPanel.jsx +++ b/frontend/src/components/workflow/panels/QuestionAugmentationPanel.jsx @@ -47,7 +47,7 @@ export function QuestionAugmentationPanel({ node, onChange }) { {questions.map((q, idx) => ( handleQuestionChange(idx, field, value)} From cb3aa48999627cfa52c627be7cde6210409d5846 Mon Sep 17 00:00:00 2001 From: Lars Date: Sun, 12 Apr 2026 13:37:31 +0200 Subject: [PATCH 2/4] fix: Add wrapper function for workflow LLM calls to prevent max_tokens signature mismatch Problem: workflow_executor calls openrouter_call_func(prompt, model) but call_openrouter expects (prompt, max_tokens=4096). This caused the model string 'anthropic/claude-sonnet-4' to be passed as max_tokens, resulting in OpenRouter requesting 64000 tokens and failing with 402 credit errors. Solution: Added workflow_llm_call() wrapper in workflows.py that matches the expected (prompt, model) -> str signature and calls call_openrouter correctly. Fixes: All workflows failing with 402 'insufficient credits' errors --- backend/routers/workflows.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/backend/routers/workflows.py b/backend/routers/workflows.py index d37f5b2..b13d52e 100644 --- a/backend/routers/workflows.py +++ b/backend/routers/workflows.py @@ -86,11 +86,19 @@ async def execute_workflow_endpoint( "type": "workflow" } + # Wrapper function to match workflow_executor's expected signature: (prompt, model) -> str + # workflow_executor calls: openrouter_call_func(prompt, "anthropic/claude-sonnet-4") + # but call_openrouter expects: call_openrouter(prompt, max_tokens=4096) + async def workflow_llm_call(prompt: str, model: str) -> str: + # Ignore model parameter (already set in OPENROUTER_MODEL env var) + # Use default max_tokens=4096 from call_openrouter + return await call_openrouter(prompt) + try: result = await execute_workflow_prompt( prompt=workflow_prompt, variables=variables, - openrouter_call_func=call_openrouter, + openrouter_call_func=workflow_llm_call, # Use wrapper with correct signature enable_debug=request.enable_debug ) return result From f6b3182a807b6dc8c1901bfe036714c5f1003b61 Mon Sep 17 00:00:00 2001 From: Lars Date: Sun, 12 Apr 2026 13:44:08 +0200 Subject: [PATCH 3/4] fix: Add wrapper in prompts.py execute endpoint for workflow signature mismatch Problem: Workflows executed via /api/prompts/execute (not /api/workflows/execute) were passing call_openrouter directly to execute_prompt_with_data, which then passes it to workflow_executor. workflow_executor expects (prompt, model) signature but call_openrouter has (prompt, max_tokens=4096) signature. Previous fix in workflows.py was correct but unused - workflows use prompts.py endpoint. Solution: Added workflow_llm_call() wrapper in execute_unified_prompt() endpoint that matches expected (prompt, model) -> str signature. Related: cb3aa48 (workflows.py fix for different endpoint) --- backend/routers/prompts.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/backend/routers/prompts.py b/backend/routers/prompts.py index 1f32011..cc438db 100644 --- a/backend/routers/prompts.py +++ b/backend/routers/prompts.py @@ -1488,6 +1488,14 @@ async def execute_unified_prompt( 'vitalwerte': 7 } + # Wrapper function to match workflow_executor's expected signature: (prompt, model) -> str + # workflow_executor calls: openrouter_call_func(prompt, "anthropic/claude-sonnet-4") + # but call_openrouter expects: call_openrouter(prompt, max_tokens=4096) + async def workflow_llm_call(prompt: str, model: str = None) -> str: + # Ignore model parameter (already set in OPENROUTER_MODEL env var) + # Use default max_tokens=4096 from call_openrouter + return await call_openrouter(prompt) + # Execute with prompt_executor # Always enable debug when saving to collect metadata for value table result = await execute_prompt_with_data( @@ -1495,7 +1503,7 @@ async def execute_unified_prompt( profile_id=profile_id, modules=modules, timeframes=timeframes, - openrouter_call_func=call_openrouter, + openrouter_call_func=workflow_llm_call, # Use wrapper with correct signature enable_debug=debug or save # Enable debug if saving for metadata collection ) From e09cbc112e4cdd007d7aac21fef11f31d39125d6 Mon Sep 17 00:00:00 2001 From: Lars Date: Sun, 12 Apr 2026 14:04:14 +0200 Subject: [PATCH 4/4] fix: Preserve case in question IDs during parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Parser converted question IDs to lowercase ('qAnalyst' → 'qanalyst'), causing normalization to fail because id_catalog lookup is case-sensitive. Impact: All workflow question signals were lost - normalized_signals stayed empty, so template placeholders like {{node_2.signal_qAnalyst}} remained unresolved. Solution: Removed .lower() call in parse_decision_questions() to preserve original case from AI response. Root cause: Line 162 in result_container_parser.py Fixes: Question augmentation signals not appearing in workflow end nodes --- backend/result_container_parser.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/result_container_parser.py b/backend/result_container_parser.py index 638e050..594e152 100644 --- a/backend/result_container_parser.py +++ b/backend/result_container_parser.py @@ -158,7 +158,8 @@ def parse_decision_questions(section_text: str) -> Dict[str, str]: for pattern in patterns: matches = re.finditer(pattern, section_text, re.MULTILINE | re.IGNORECASE) for match in matches: - question_type = match.group(1).strip().lower() + # Preserve original case for question IDs (e.g., "qAnalyst" not "qanalyst") + question_type = match.group(1).strip() answer = match.group(2).strip() # Entferne Klammern und Whitespace