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"),