From 160766be2a10db04d14c462c2f0e313096a98c8b Mon Sep 17 00:00:00 2001 From: ValueOn AG Date: Tue, 4 Nov 2025 22:10:29 +0100 Subject: [PATCH] RELEASED v 4.0. --- modules/interfaces/interfaceDbChatObjects.py | 86 +++++++++++++++++++- modules/workflows/methods/methodAi.py | 4 +- 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/modules/interfaces/interfaceDbChatObjects.py b/modules/interfaces/interfaceDbChatObjects.py index c8d770ee..35ed2f32 100644 --- a/modules/interfaces/interfaceDbChatObjects.py +++ b/modules/interfaces/interfaceDbChatObjects.py @@ -1390,7 +1390,77 @@ class ChatObjects: result = template for placeholderName, value in placeholders.items(): pattern = f"{{{{KEY:{placeholderName}}}}}" - result = result.replace(pattern, str(value)) + + # Check if placeholder is in an array context like ["{{KEY:...}}"] + # If value is a JSON array/dict, we should replace the entire ["{{KEY:...}}"] with the array + arrayPattern = f'["{pattern}"]' + if arrayPattern in result: + # Check if value is a JSON array/dict + isArrayValue = False + arrayValue = None + + if isinstance(value, (list, dict)): + isArrayValue = True + arrayValue = json.dumps(value) + elif isinstance(value, str): + try: + parsed = json.loads(value) + if isinstance(parsed, (list, dict)): + isArrayValue = True + arrayValue = value # Already valid JSON string + except (json.JSONDecodeError, ValueError): + pass + + if isArrayValue: + # Replace ["{{KEY:...}}"] with the array value + result = result.replace(arrayPattern, arrayValue) + continue # Skip the regular replacement below + + # Regular replacement - check if in quoted context + patternStart = result.find(pattern) + isQuoted = False + if patternStart > 0: + charBefore = result[patternStart - 1] if patternStart > 0 else None + patternEnd = patternStart + len(pattern) + charAfter = result[patternEnd] if patternEnd < len(result) else None + if charBefore == '"' and charAfter == '"': + isQuoted = True + + # Handle different value types + if isinstance(value, (list, dict)): + # Python list/dict - convert to JSON + replacement = json.dumps(value) + elif isinstance(value, str): + # String value - check if it's a JSON string representing list/dict + try: + parsed = json.loads(value) + if isinstance(parsed, (list, dict)): + # It's a JSON string of a list/dict + if isQuoted: + # In quoted context, escape the JSON string + escaped = json.dumps(value) + replacement = escaped[1:-1] # Remove outer quotes + else: + # In unquoted context, use JSON directly + replacement = value + else: + # It's a JSON string of a primitive + if isQuoted: + escaped = json.dumps(value) + replacement = escaped[1:-1] + else: + replacement = value + except (json.JSONDecodeError, ValueError): + # Not valid JSON - treat as plain string + if isQuoted: + escaped = json.dumps(value) + replacement = escaped[1:-1] + else: + replacement = value + else: + # Numbers, booleans, None - convert to string + replacement = str(value) + result = result.replace(pattern, replacement) return result def _parseScheduleToCron(self, schedule: str) -> Dict[str, Any]: @@ -1429,7 +1499,19 @@ class ChatObjects: template = automation.get("template", "") placeholders = automation.get("placeholders", {}) planJson = self._replacePlaceholders(template, placeholders) - plan = json.loads(planJson) + try: + plan = json.loads(planJson) + except json.JSONDecodeError as e: + logger.error(f"Failed to parse plan JSON after placeholder replacement: {str(e)}") + logger.error(f"Template: {template[:500]}...") + logger.error(f"Placeholders: {placeholders}") + logger.error(f"Generated planJson (first 1000 chars): {planJson[:1000]}") + logger.error(f"Error position: line {e.lineno}, column {e.colno}, char {e.pos}") + if e.pos: + start = max(0, e.pos - 100) + end = min(len(planJson), e.pos + 100) + logger.error(f"Context around error: ...{planJson[start:end]}...") + raise ValueError(f"Invalid JSON after placeholder replacement: {str(e)}") executionLog["messages"].append("Template placeholders replaced successfully") # 3. Get user who created automation diff --git a/modules/workflows/methods/methodAi.py b/modules/workflows/methods/methodAi.py index a1206ba6..b1fd7cb6 100644 --- a/modules/workflows/methods/methodAi.py +++ b/modules/workflows/methods/methodAi.py @@ -175,7 +175,7 @@ class MethodAi(MethodBase): Parameters: - prompt (str, required): Natural language research instruction. - - list(url) (list, optional): Specific URLs to crawl, if needed. + - urlList (list, optional): Specific URLs to crawl, if needed. - country (str, optional): Two-digit country code (lowercase, e.g., ch, us, de). - language (str, optional): Language code (lowercase, e.g., de, en, fr). - researchDepth (str, optional): Research depth - fast, general, or deep. Default: general. @@ -199,7 +199,7 @@ class MethodAi(MethodBase): # Call webcrawl service - service handles all AI intention analysis and processing result = await self.services.web.performWebResearch( prompt=prompt, - urls=parameters.get("list(url)", []), + urls=parameters.get("urlList", []), country=parameters.get("country"), language=parameters.get("language"), researchDepth=parameters.get("researchDepth", "general"),