From 4418dfb604fc1a1c160fff7c7293fdc02cc5c3a5 Mon Sep 17 00:00:00 2001
From: ValueOn AG
Date: Thu, 4 Dec 2025 11:12:45 +0100
Subject: [PATCH] fixed issues
---
modules/aicore/aicorePluginAnthropic.py | 5 +-
.../processing/adaptive/contentValidator.py | 46 ++++++++++++++-----
.../workflows/processing/modes/modeDynamic.py | 4 +-
.../workflows/processing/workflowProcessor.py | 4 +-
4 files changed, 42 insertions(+), 17 deletions(-)
diff --git a/modules/aicore/aicorePluginAnthropic.py b/modules/aicore/aicorePluginAnthropic.py
index 50bcf3ca..de8a312f 100644
--- a/modules/aicore/aicorePluginAnthropic.py
+++ b/modules/aicore/aicorePluginAnthropic.py
@@ -44,9 +44,8 @@ class AiAnthropic(BaseConnectorAi):
return "anthropic"
def getModels(self) -> List[AiModel]:
- return [] # TODO: DEBUG TO TURN ON AFTER TESTING
-
- """Get all available Anthropic models."""
+ # return [] # TODO: DEBUG TO TURN ON AFTER TESTING
+ # Get all available Anthropic models.
return [
AiModel(
name="claude-sonnet-4-5-20250929",
diff --git a/modules/workflows/processing/adaptive/contentValidator.py b/modules/workflows/processing/adaptive/contentValidator.py
index ebb433da..355497de 100644
--- a/modules/workflows/processing/adaptive/contentValidator.py
+++ b/modules/workflows/processing/adaptive/contentValidator.py
@@ -22,7 +22,7 @@ class ContentValidator:
self.services = services
self.learningEngine = learningEngine
- async def validateContent(self, documents: List[Any], intent: Dict[str, Any], taskStep: Optional[Any] = None, actionName: Optional[str] = None, actionParameters: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
+ async def validateContent(self, documents: List[Any], intent: Dict[str, Any], taskStep: Optional[Any] = None, actionName: Optional[str] = None, actionParameters: Optional[Dict[str, Any]] = None, actionHistory: Optional[List[Dict[str, Any]]] = None) -> Dict[str, Any]:
"""Validates delivered content against user intent using AI (single attempt; parse-or-fail)
Args:
@@ -31,8 +31,9 @@ class ContentValidator:
taskStep: Optional TaskStep object (preferred source for objective)
actionName: Optional action name (e.g., "ai.process", "ai.webResearch") that created the documents
actionParameters: Optional action parameters used during execution (e.g., {"columnsPerRow": 10, "researchDepth": "deep"})
+ actionHistory: Optional list of previously executed actions in the workflow (for multi-step workflow context)
"""
- return await self._validateWithAI(documents, intent, taskStep, actionName, actionParameters)
+ return await self._validateWithAI(documents, intent, taskStep, actionName, actionParameters, actionHistory)
def _analyzeDocuments(self, documents: List[Any]) -> List[Dict[str, Any]]:
"""Generic document analysis - create simple summaries with metadata."""
@@ -391,7 +392,7 @@ class ContentValidator:
return False
- async def _validateWithAI(self, documents: List[Any], intent: Dict[str, Any], taskStep: Optional[Any] = None, actionName: Optional[str] = None, actionParameters: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
+ async def _validateWithAI(self, documents: List[Any], intent: Dict[str, Any], taskStep: Optional[Any] = None, actionName: Optional[str] = None, actionParameters: Optional[Dict[str, Any]] = None, actionHistory: Optional[List[Dict[str, Any]]] = None) -> Dict[str, Any]:
"""AI-based comprehensive validation - generic approach"""
try:
if not hasattr(self, 'services') or not self.services or not hasattr(self.services, 'ai'):
@@ -474,6 +475,26 @@ class ContentValidator:
metadataJson = json.dumps(combinedMetadata, ensure_ascii=False, indent=2)
validationMetadataContext = f"\nACTION VALIDATION METADATA: {metadataJson}"
+ # Build action history context (for multi-step workflow validation)
+ actionHistoryContext = ""
+ if actionHistory and isinstance(actionHistory, list) and len(actionHistory) > 0:
+ historyEntries = []
+ for entry in actionHistory:
+ if isinstance(entry, dict):
+ action = entry.get('action', 'unknown')
+ params = entry.get('parameters', {}) or {}
+ step = entry.get('step', 0)
+ # Filter out documentList for clarity
+ relevantParams = {k: v for k, v in params.items() if k not in ['documentList', 'connections'] and v is not None}
+ paramsStr = json.dumps(relevantParams, ensure_ascii=False) if relevantParams else "{}"
+ historyEntries.append(f"Step {step}: {action} {paramsStr}")
+ elif isinstance(entry, str):
+ historyEntries.append(entry)
+
+ if historyEntries:
+ actionHistoryContext = f"\n\n=== ACTION HISTORY ===\n" + "\n".join(f"- {entry}" for entry in historyEntries)
+ actionHistoryContext += "\n\nIMPORTANT: This shows the complete workflow that produced the documents. For process-oriented criteria (e.g., 'internet search performed'), check ACTION HISTORY first. Document metadata may only reflect the LAST action, not the entire workflow."
+
# Format success criteria for display with index numbers
if successCriteria:
criteriaDisplay = "\n".join([f"[{i}] {criterion}" for i, criterion in enumerate(successCriteria)])
@@ -485,22 +506,25 @@ class ContentValidator:
=== TASK INFORMATION ===
{objectiveLabel}: '{objectiveText}'
EXPECTED DATA TYPE: {dataType}
-EXPECTED FORMATS: {expectedFormats if expectedFormats else ['any']}{actionContext}{actionParamsContext}{validationMetadataContext}
+EXPECTED FORMATS: {expectedFormats if expectedFormats else ['any']}{actionContext}{actionParamsContext}{validationMetadataContext}{actionHistoryContext}
=== VALIDATION INSTRUCTIONS ===
IMPORTANT: Different formats can represent the same data structure. Do not reject a format just because it differs from expected - check the structure summary for actual content.
VALIDATION RULES:
-1. Use structure summary (sections, statistics, counts) as PRIMARY evidence. Trust structure over format claims.
-2. For each criterion in criteriaMapping: evaluate ONLY that criterion. Do not mention other criteria.
-3. Priority: Data completeness > Format compatibility. Missing data is more critical than format mismatch.
-4. Format understanding: Different formats can represent equivalent data structures. Focus on content, not format name.
-5. Data availability assessment: If delivered documents do not contain required data, clearly indicate this in findings. Re-reading the same documents might not help.
+1. Use structure summary (sections, statistics, counts) as PRIMARY evidence for DATA-ORIENTED criteria. Trust structure over format claims.
+2. Use ACTION HISTORY as PRIMARY evidence for PROCESS-ORIENTED criteria (e.g., "internet search performed", "sources cited"). Document metadata may only reflect the last action, not the entire workflow.
+3. For each criterion in criteriaMapping: evaluate ONLY that criterion. Do not mention other criteria.
+4. Priority: Data completeness > Format compatibility. Missing data is more critical than format mismatch.
+5. Format understanding: Different formats can represent equivalent data structures. Focus on content, not format name.
+6. Multi-step workflow awareness: If ACTION HISTORY is present, consider the workflow as a whole. Document metadata (e.g., extraction_method) describes how data was EXTRACTED in the last step, not necessarily how it was OBTAINED in the workflow.
+7. Data availability assessment: If delivered documents do not contain required data, clearly indicate this in findings. Re-reading the same documents might not help.
VALIDATION STEPS:
-- Check ACTION VALIDATION METADATA first (if present) - this contains action-specific context
-- Check structure summary for quantities, counts, statistics
+- Check ACTION HISTORY first (if present) for PROCESS-ORIENTED criteria (e.g., "search performed", "sources used", "verification done")
+- Check ACTION VALIDATION METADATA (if present) - this contains action-specific context for the LAST action only
+- Check structure summary for quantities, counts, statistics (for DATA-ORIENTED criteria)
- Compare found values with required values from criteria
- If structure unavailable, use metadata only (format, filename, size)
- Classify gaps: missing_data (less than required), incomplete_data (partial), wrong_structure (wrong organization), wrong_format (format mismatch but data present)
diff --git a/modules/workflows/processing/modes/modeDynamic.py b/modules/workflows/processing/modes/modeDynamic.py
index 592b5235..515deaaa 100644
--- a/modules/workflows/processing/modes/modeDynamic.py
+++ b/modules/workflows/processing/modes/modeDynamic.py
@@ -152,9 +152,11 @@ class DynamicMode(BaseMode):
# Pass taskStep so validator can use task.objective and format fields
# Pass action name so validator knows which action created the documents
# Pass action parameters so validator can verify parameter-specific requirements
+ # Pass action history so validator can validate process-oriented criteria in multi-step workflows
actionName = selection.get('action', 'unknown')
actionParameters = selection.get('parameters', {})
- validationResult = await self.contentValidator.validateContent(result.documents, self.workflowIntent, taskStep, actionName, actionParameters)
+ actionHistory = getattr(context, 'executedActions', None) if hasattr(context, 'executedActions') else None
+ validationResult = await self.contentValidator.validateContent(result.documents, self.workflowIntent, taskStep, actionName, actionParameters, actionHistory)
observation.contentValidation = validationResult
quality_score = validationResult.get('qualityScore', 0.0)
if quality_score is None:
diff --git a/modules/workflows/processing/workflowProcessor.py b/modules/workflows/processing/workflowProcessor.py
index 403bf008..f33df591 100644
--- a/modules/workflows/processing/workflowProcessor.py
+++ b/modules/workflows/processing/workflowProcessor.py
@@ -357,8 +357,8 @@ class WorkflowProcessor:
"- Need for previous workflow rounds/history (e.g., 'continue', 'retry', 'fix', 'improve', 'update', 'modify', 'based on previous', 'build on', references to earlier work)\n"
"- Language: Detect the ISO 639-1 language code (e.g., de, en, fr, it) from the user's request\n\n"
"Complexity levels:\n"
- "- 'simple': Single question, no documents or minimal documents, straightforward answer that can be provided in one AI response (5-15s)\n"
- "- 'moderate': Multiple steps, some documents, structured response requiring some processing (30-60s)\n"
+ "- 'simple': Only if NO documents AND NO web search required. Single question, straightforward answer that can be provided in one AI response (5-15s)\n"
+ "- 'moderate': Multiple steps, some documents, structured response requiring some processing, or web search needed (30-60s)\n"
"- 'complex': Multi-task workflow, many documents, research needed, content generation required, multi-step planning (60-120s)\n\n"
"Return ONLY a JSON object with this exact structure:\n"
"{\n"