cleaned pydantic model classes
This commit is contained in:
parent
6b976fc1ca
commit
d2b6820812
35 changed files with 492 additions and 667 deletions
|
|
@ -10,7 +10,6 @@ from . import datamodelWeb as web
|
|||
from . import datamodelUam as uam
|
||||
from . import datamodelSecurity as security
|
||||
from . import datamodelNeutralizer as neutralizer
|
||||
from . import datamodelWorkflow as workflow
|
||||
from . import datamodelChat as chat
|
||||
from . import datamodelFiles as files
|
||||
from . import datamodelVoice as voice
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ from modules.shared.attributeUtils import register_model_labels, ModelMixin
|
|||
from modules.shared.timezoneUtils import get_utc_timestamp
|
||||
import uuid
|
||||
|
||||
|
||||
class ChatStat(BaseModel, ModelMixin):
|
||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key")
|
||||
workflowId: Optional[str] = Field(None, description="Foreign key to workflow (for workflow stats)")
|
||||
|
|
@ -17,8 +16,6 @@ class ChatStat(BaseModel, ModelMixin):
|
|||
bytesReceived: Optional[int] = Field(None, description="Number of bytes received")
|
||||
successRate: Optional[float] = Field(None, description="Success rate of operations")
|
||||
errorCount: Optional[int] = Field(None, description="Number of errors encountered")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"ChatStat",
|
||||
{"en": "Chat Statistics", "fr": "Statistiques de chat"},
|
||||
|
|
@ -35,7 +32,6 @@ register_model_labels(
|
|||
},
|
||||
)
|
||||
|
||||
|
||||
class ChatLog(BaseModel, ModelMixin):
|
||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key")
|
||||
workflowId: str = Field(description="Foreign key to workflow")
|
||||
|
|
@ -45,8 +41,6 @@ class ChatLog(BaseModel, ModelMixin):
|
|||
status: Optional[str] = Field(None, description="Status of the log entry")
|
||||
progress: Optional[float] = Field(None, description="Progress indicator (0.0 to 1.0)")
|
||||
performance: Optional[Dict[str, Any]] = Field(None, description="Performance metrics")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"ChatLog",
|
||||
{"en": "Chat Log", "fr": "Journal de chat"},
|
||||
|
|
@ -62,7 +56,6 @@ register_model_labels(
|
|||
},
|
||||
)
|
||||
|
||||
|
||||
class ChatDocument(BaseModel, ModelMixin):
|
||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key")
|
||||
messageId: str = Field(description="Foreign key to message")
|
||||
|
|
@ -74,8 +67,6 @@ class ChatDocument(BaseModel, ModelMixin):
|
|||
taskNumber: Optional[int] = Field(None, description="Task number within round")
|
||||
actionNumber: Optional[int] = Field(None, description="Action number within task")
|
||||
actionId: Optional[str] = Field(None, description="ID of the action that created this document")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"ChatDocument",
|
||||
{"en": "Chat Document", "fr": "Document de chat"},
|
||||
|
|
@ -93,7 +84,6 @@ register_model_labels(
|
|||
},
|
||||
)
|
||||
|
||||
|
||||
class ContentMetadata(BaseModel, ModelMixin):
|
||||
size: int = Field(description="Content size in bytes")
|
||||
pages: Optional[int] = Field(None, description="Number of pages for multi-page content")
|
||||
|
|
@ -105,8 +95,6 @@ class ContentMetadata(BaseModel, ModelMixin):
|
|||
durationSec: Optional[float] = Field(None, description="Duration in seconds for media")
|
||||
mimeType: str = Field(description="MIME type of the content")
|
||||
base64Encoded: bool = Field(description="Whether the data is base64 encoded")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"ContentMetadata",
|
||||
{"en": "Content Metadata", "fr": "Métadonnées du contenu"},
|
||||
|
|
@ -124,13 +112,10 @@ register_model_labels(
|
|||
},
|
||||
)
|
||||
|
||||
|
||||
class ContentItem(BaseModel, ModelMixin):
|
||||
label: str = Field(description="Content label")
|
||||
data: str = Field(description="Extracted text content")
|
||||
metadata: ContentMetadata = Field(description="Content metadata")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"ContentItem",
|
||||
{"en": "Content Item", "fr": "Élément de contenu"},
|
||||
|
|
@ -141,14 +126,11 @@ register_model_labels(
|
|||
},
|
||||
)
|
||||
|
||||
|
||||
class ExtractedContent(BaseModel, ModelMixin):
|
||||
class ChatContentExtracted(BaseModel, ModelMixin):
|
||||
id: str = Field(description="Reference to source ChatDocument")
|
||||
contents: List[ContentItem] = Field(default_factory=list, description="List of content items")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"ExtractedContent",
|
||||
"ChatContentExtracted",
|
||||
{"en": "Extracted Content", "fr": "Contenu extrait"},
|
||||
{
|
||||
"id": {"en": "Object ID", "fr": "ID de l'objet"},
|
||||
|
|
@ -177,8 +159,6 @@ class ChatMessage(BaseModel, ModelMixin):
|
|||
actionNumber: Optional[int] = Field(None, description="Action number within task")
|
||||
taskProgress: Optional[str] = Field(None, description="Task progress status: pending, running, success, fail, retry")
|
||||
actionProgress: Optional[str] = Field(None, description="Action progress status: pending, running, success, fail")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"ChatMessage",
|
||||
{"en": "Chat Message", "fr": "Message de chat"},
|
||||
|
|
@ -206,7 +186,6 @@ register_model_labels(
|
|||
},
|
||||
)
|
||||
|
||||
|
||||
class ChatWorkflow(BaseModel, ModelMixin):
|
||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||
mandateId: str = Field(description="ID of the mandate this workflow belongs to", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||
|
|
@ -233,8 +212,6 @@ class ChatWorkflow(BaseModel, ModelMixin):
|
|||
{"value": "React", "label": {"en": "React", "fr": "Réactif"}},
|
||||
])
|
||||
maxSteps: int = Field(default=5, description="Maximum number of iterations in react mode", frontend_type="integer", frontend_readonly=False, frontend_required=False)
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"ChatWorkflow",
|
||||
{"en": "Chat Workflow", "fr": "Flux de travail de chat"},
|
||||
|
|
@ -259,41 +236,12 @@ register_model_labels(
|
|||
},
|
||||
)
|
||||
|
||||
|
||||
class WorkflowResult(BaseModel, ModelMixin):
|
||||
status: str
|
||||
completed_tasks: int
|
||||
total_tasks: int
|
||||
execution_time: float
|
||||
final_results_count: int
|
||||
error: Optional[str] = None
|
||||
phase: Optional[str] = None
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"WorkflowResult",
|
||||
{"en": "Workflow Result", "fr": "Résultat du workflow"},
|
||||
{
|
||||
"status": {"en": "Status", "fr": "Statut"},
|
||||
"completed_tasks": {"en": "Completed Tasks", "fr": "Tâches terminées"},
|
||||
"total_tasks": {"en": "Total Tasks", "fr": "Total des tâches"},
|
||||
"execution_time": {"en": "Execution Time", "fr": "Temps d'exécution"},
|
||||
"final_results_count": {"en": "Final Results Count", "fr": "Nombre de résultats finaux"},
|
||||
"error": {"en": "Error", "fr": "Erreur"},
|
||||
"phase": {"en": "Phase", "fr": "Phase"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class UserInputRequest(BaseModel, ModelMixin):
|
||||
prompt: str = Field(description="Prompt for the user")
|
||||
listFileId: List[str] = Field(default_factory=list, description="List of file IDs")
|
||||
userLanguage: str = Field(default="en", description="User's preferred language")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"UserInputRequest",
|
||||
{"en": "User Input Request", "fr": "Demande de saisie utilisateur"},
|
||||
"UserInputRequest", {"en": "User Input Request", "fr": "Demande de saisie utilisateur"},
|
||||
{
|
||||
"prompt": {"en": "Prompt", "fr": "Invite"},
|
||||
"listFileId": {"en": "File IDs", "fr": "IDs des fichiers"},
|
||||
|
|
@ -301,4 +249,389 @@ register_model_labels(
|
|||
},
|
||||
)
|
||||
|
||||
class ActionDocument(BaseModel, ModelMixin):
|
||||
"""Clear document structure for action results"""
|
||||
documentName: str = Field(description="Name of the document")
|
||||
documentData: Any = Field(description="Content/data of the document")
|
||||
mimeType: str = Field(description="MIME type of the document")
|
||||
register_model_labels(
|
||||
"ActionDocument",
|
||||
{"en": "Action Document", "fr": "Document d'action"},
|
||||
{
|
||||
"documentName": {"en": "Document Name", "fr": "Nom du document"},
|
||||
"documentData": {"en": "Document Data", "fr": "Données du document"},
|
||||
"mimeType": {"en": "MIME Type", "fr": "Type MIME"},
|
||||
},
|
||||
)
|
||||
|
||||
class ActionResult(BaseModel, ModelMixin):
|
||||
"""Clean action result with documents as primary output
|
||||
|
||||
IMPORTANT: Action methods should NOT set resultLabel in their return value.
|
||||
The resultLabel is managed by the action handler using the action's execResultLabel
|
||||
from the action plan. This ensures consistent document routing throughout the workflow.
|
||||
"""
|
||||
|
||||
success: bool = Field(description="Whether execution succeeded")
|
||||
error: Optional[str] = Field(None, description="Error message if failed")
|
||||
documents: List[ActionDocument] = Field(default_factory=list, description="Document outputs")
|
||||
resultLabel: Optional[str] = Field(None, description="Label for document routing (set by action handler, not by action methods)")
|
||||
|
||||
@classmethod
|
||||
def isSuccess(cls, documents: List[ActionDocument] = None) -> "ActionResult":
|
||||
return cls(success=True, documents=documents or [])
|
||||
|
||||
@classmethod
|
||||
def isFailure(cls, error: str, documents: List[ActionDocument] = None) -> "ActionResult":
|
||||
return cls(success=False, documents=documents or [], error=error)
|
||||
register_model_labels(
|
||||
"ActionResult",
|
||||
{"en": "Action Result", "fr": "Résultat de l'action"},
|
||||
{
|
||||
"success": {"en": "Success", "fr": "Succès"},
|
||||
"error": {"en": "Error", "fr": "Erreur"},
|
||||
"documents": {"en": "Documents", "fr": "Documents"},
|
||||
"resultLabel": {"en": "Result Label", "fr": "Étiquette du résultat"},
|
||||
},
|
||||
)
|
||||
|
||||
class ActionSelection(BaseModel, ModelMixin):
|
||||
method: str = Field(description="Method to execute (e.g., web, document, ai)")
|
||||
name: str = Field(description="Action name within the method (e.g., search, extract)")
|
||||
register_model_labels(
|
||||
"ActionSelection",
|
||||
{"en": "Action Selection", "fr": "Sélection d'action"},
|
||||
{
|
||||
"method": {"en": "Method", "fr": "Méthode"},
|
||||
"name": {"en": "Action Name", "fr": "Nom de l'action"},
|
||||
},
|
||||
)
|
||||
|
||||
class ActionParameters(BaseModel, ModelMixin):
|
||||
parameters: Dict[str, Any] = Field(default_factory=dict, description="Parameters to execute the selected action")
|
||||
register_model_labels(
|
||||
"ActionParameters",
|
||||
{"en": "Action Parameters", "fr": "Paramètres d'action"},
|
||||
{
|
||||
"parameters": {"en": "Parameters", "fr": "Paramètres"},
|
||||
},
|
||||
)
|
||||
|
||||
class ObservationPreview(BaseModel, ModelMixin):
|
||||
name: str = Field(description="Document name or URL label")
|
||||
mime: str = Field(description="MIME type or kind")
|
||||
snippet: str = Field(description="Short snippet or summary")
|
||||
register_model_labels(
|
||||
"ObservationPreview",
|
||||
{"en": "Observation Preview", "fr": "Aperçu d'observation"},
|
||||
{
|
||||
"name": {"en": "Name", "fr": "Nom"},
|
||||
"mime": {"en": "MIME", "fr": "MIME"},
|
||||
"snippet": {"en": "Snippet", "fr": "Extrait"},
|
||||
},
|
||||
)
|
||||
|
||||
class Observation(BaseModel, ModelMixin):
|
||||
success: bool = Field(description="Action execution success flag")
|
||||
resultLabel: str = Field(description="Deterministic label for produced documents")
|
||||
documentsCount: int = Field(description="Number of produced documents")
|
||||
previews: List[ObservationPreview] = Field(default_factory=list, description="Compact previews of outputs")
|
||||
notes: List[str] = Field(default_factory=list, description="Short notes or key facts")
|
||||
register_model_labels(
|
||||
"Observation",
|
||||
{"en": "Observation", "fr": "Observation"},
|
||||
{
|
||||
"success": {"en": "Success", "fr": "Succès"},
|
||||
"resultLabel": {"en": "Result Label", "fr": "Étiquette du résultat"},
|
||||
"documentsCount": {"en": "Documents Count", "fr": "Nombre de documents"},
|
||||
"previews": {"en": "Previews", "fr": "Aperçus"},
|
||||
"notes": {"en": "Notes", "fr": "Notes"},
|
||||
},
|
||||
)
|
||||
|
||||
class TaskStatus(str):
|
||||
PENDING = "pending"
|
||||
RUNNING = "running"
|
||||
COMPLETED = "completed"
|
||||
FAILED = "failed"
|
||||
CANCELLED = "cancelled"
|
||||
register_model_labels(
|
||||
"TaskStatus",
|
||||
{"en": "Task Status", "fr": "Statut de la tâche"},
|
||||
{
|
||||
"PENDING": {"en": "Pending", "fr": "En attente"},
|
||||
"RUNNING": {"en": "Running", "fr": "En cours"},
|
||||
"COMPLETED": {"en": "Completed", "fr": "Terminé"},
|
||||
"FAILED": {"en": "Failed", "fr": "Échec"},
|
||||
"CANCELLED": {"en": "Cancelled", "fr": "Annulé"},
|
||||
},
|
||||
)
|
||||
|
||||
class DocumentExchange(BaseModel, ModelMixin):
|
||||
documentsLabel: str = Field(description="Label for the set of documents")
|
||||
documents: List[str] = Field(default_factory=list, description="List of document references")
|
||||
register_model_labels(
|
||||
"DocumentExchange",
|
||||
{"en": "Document Exchange", "fr": "Échange de documents"},
|
||||
{
|
||||
"documentsLabel": {"en": "Documents Label", "fr": "Label des documents"},
|
||||
"documents": {"en": "Documents", "fr": "Documents"},
|
||||
},
|
||||
)
|
||||
|
||||
class ActionItem(BaseModel, ModelMixin):
|
||||
id: str = Field(..., description="Action ID")
|
||||
execMethod: str = Field(..., description="Method to execute")
|
||||
execAction: str = Field(..., description="Action to perform")
|
||||
execParameters: Dict[str, Any] = Field(default_factory=dict, description="Action parameters")
|
||||
execResultLabel: Optional[str] = Field(None, description="Label for the set of result documents")
|
||||
expectedDocumentFormats: Optional[List[Dict[str, str]]] = Field(None, description="Expected document formats (optional)")
|
||||
userMessage: Optional[str] = Field(None, description="User-friendly message in user's language")
|
||||
status: TaskStatus = Field(default=TaskStatus.PENDING, description="Action status")
|
||||
error: Optional[str] = Field(None, description="Error message if action failed")
|
||||
retryCount: int = Field(default=0, description="Number of retries attempted")
|
||||
retryMax: int = Field(default=3, description="Maximum number of retries")
|
||||
processingTime: Optional[float] = Field(None, description="Processing time in seconds")
|
||||
timestamp: float = Field(..., description="When the action was executed (UTC timestamp in seconds)")
|
||||
result: Optional[str] = Field(None, description="Result of the action")
|
||||
|
||||
def setSuccess(self, result: str = None) -> None:
|
||||
"""Set the action as successful with optional result"""
|
||||
self.status = TaskStatus.COMPLETED
|
||||
self.error = None
|
||||
if result is not None:
|
||||
self.result = result
|
||||
|
||||
def setError(self, error_message: str) -> None:
|
||||
"""Set the action as failed with error message"""
|
||||
self.status = TaskStatus.FAILED
|
||||
self.error = error_message
|
||||
register_model_labels(
|
||||
"ActionItem",
|
||||
{"en": "Task Action", "fr": "Action de tâche"},
|
||||
{
|
||||
"id": {"en": "Action ID", "fr": "ID de l'action"},
|
||||
"execMethod": {"en": "Method", "fr": "Méthode"},
|
||||
"execAction": {"en": "Action", "fr": "Action"},
|
||||
"execParameters": {"en": "Parameters", "fr": "Paramètres"},
|
||||
"execResultLabel": {"en": "Result Label", "fr": "Label du résultat"},
|
||||
"expectedDocumentFormats": {"en": "Expected Document Formats", "fr": "Formats de documents attendus"},
|
||||
"userMessage": {"en": "User Message", "fr": "Message utilisateur"},
|
||||
"status": {"en": "Status", "fr": "Statut"},
|
||||
"error": {"en": "Error", "fr": "Erreur"},
|
||||
"retryCount": {"en": "Retry Count", "fr": "Nombre de tentatives"},
|
||||
"retryMax": {"en": "Max Retries", "fr": "Tentatives max"},
|
||||
"processingTime": {"en": "Processing Time", "fr": "Temps de traitement"},
|
||||
"timestamp": {"en": "Timestamp", "fr": "Horodatage"},
|
||||
"result": {"en": "Result", "fr": "Résultat"},
|
||||
},
|
||||
)
|
||||
|
||||
class TaskResult(BaseModel, ModelMixin):
|
||||
taskId: str = Field(..., description="Task ID")
|
||||
status: TaskStatus = Field(default=TaskStatus.PENDING, description="Task status")
|
||||
success: bool = Field(..., description="Whether the task was successful")
|
||||
feedback: Optional[str] = Field(None, description="Task feedback message")
|
||||
error: Optional[str] = Field(None, description="Error message if task failed")
|
||||
register_model_labels(
|
||||
"TaskResult",
|
||||
{"en": "Task Result", "fr": "Résultat de tâche"},
|
||||
{
|
||||
"taskId": {"en": "Task ID", "fr": "ID de la tâche"},
|
||||
"status": {"en": "Status", "fr": "Statut"},
|
||||
"success": {"en": "Success", "fr": "Succès"},
|
||||
"feedback": {"en": "Feedback", "fr": "Retour"},
|
||||
"error": {"en": "Error", "fr": "Erreur"},
|
||||
},
|
||||
)
|
||||
|
||||
class TaskItem(BaseModel, ModelMixin):
|
||||
id: str = Field(..., description="Task ID")
|
||||
workflowId: str = Field(..., description="Workflow ID")
|
||||
userInput: str = Field(..., description="User input that triggered the task")
|
||||
status: TaskStatus = Field(default=TaskStatus.PENDING, description="Task status")
|
||||
error: Optional[str] = Field(None, description="Error message if task failed")
|
||||
startedAt: Optional[float] = Field(None, description="When the task started (UTC timestamp in seconds)")
|
||||
finishedAt: Optional[float] = Field(None, description="When the task finished (UTC timestamp in seconds)")
|
||||
actionList: List[ActionItem] = Field(default_factory=list, description="List of actions to execute")
|
||||
retryCount: int = Field(default=0, description="Number of retries attempted")
|
||||
retryMax: int = Field(default=3, description="Maximum number of retries")
|
||||
rollbackOnFailure: bool = Field(default=True, description="Whether to rollback on failure")
|
||||
dependencies: List[str] = Field(default_factory=list, description="List of task IDs this task depends on")
|
||||
feedback: Optional[str] = Field(None, description="Task feedback message")
|
||||
processingTime: Optional[float] = Field(None, description="Total processing time in seconds")
|
||||
resultLabels: Optional[Dict[str, Any]] = Field(default_factory=dict, description="Map of result labels to their values")
|
||||
register_model_labels(
|
||||
"TaskItem",
|
||||
{"en": "Task", "fr": "Tâche"},
|
||||
{
|
||||
"id": {"en": "Task ID", "fr": "ID de la tâche"},
|
||||
"workflowId": {"en": "Workflow ID", "fr": "ID du workflow"},
|
||||
"userInput": {"en": "User Input", "fr": "Entrée utilisateur"},
|
||||
"status": {"en": "Status", "fr": "Statut"},
|
||||
"error": {"en": "Error", "fr": "Erreur"},
|
||||
"startedAt": {"en": "Started At", "fr": "Démarré à"},
|
||||
"finishedAt": {"en": "Finished At", "fr": "Terminé à"},
|
||||
"actionList": {"en": "Actions", "fr": "Actions"},
|
||||
"retryCount": {"en": "Retry Count", "fr": "Nombre de tentatives"},
|
||||
"retryMax": {"en": "Max Retries", "fr": "Tentatives max"},
|
||||
"processingTime": {"en": "Processing Time", "fr": "Temps de traitement"},
|
||||
},
|
||||
)
|
||||
|
||||
class TaskStep(BaseModel, ModelMixin):
|
||||
id: str
|
||||
objective: str
|
||||
dependencies: Optional[list[str]] = Field(default_factory=list)
|
||||
success_criteria: Optional[list[str]] = Field(default_factory=list)
|
||||
estimated_complexity: Optional[str] = None
|
||||
userMessage: Optional[str] = Field(None, description="User-friendly message in user's language")
|
||||
register_model_labels(
|
||||
"TaskStep",
|
||||
{"en": "Task Step", "fr": "Étape de tâche"},
|
||||
{
|
||||
"id": {"en": "ID", "fr": "ID"},
|
||||
"objective": {"en": "Objective", "fr": "Objectif"},
|
||||
"dependencies": {"en": "Dependencies", "fr": "Dépendances"},
|
||||
"success_criteria": {"en": "Success Criteria", "fr": "Critères de succès"},
|
||||
"estimated_complexity": {"en": "Estimated Complexity", "fr": "Complexité estimée"},
|
||||
"userMessage": {"en": "User Message", "fr": "Message utilisateur"},
|
||||
},
|
||||
)
|
||||
|
||||
class TaskHandover(BaseModel, ModelMixin):
|
||||
taskId: str = Field(description="Target task ID")
|
||||
sourceTask: Optional[str] = Field(None, description="Source task ID")
|
||||
inputDocuments: List[DocumentExchange] = Field(default_factory=list, description="Available input documents")
|
||||
outputDocuments: List[DocumentExchange] = Field(default_factory=list, description="Produced output documents")
|
||||
context: Dict[str, Any] = Field(default_factory=dict, description="Task context")
|
||||
previousResults: List[str] = Field(default_factory=list, description="Previous result summaries")
|
||||
improvements: List[str] = Field(default_factory=list, description="Improvement suggestions")
|
||||
workflowSummary: Optional[str] = Field(None, description="Summarized workflow context")
|
||||
messageHistory: List[str] = Field(default_factory=list, description="Key message summaries")
|
||||
timestamp: float = Field(..., description="When the handover was created (UTC timestamp in seconds)")
|
||||
handoverType: str = Field(default="task", description="Type of handover: task, phase, or workflow")
|
||||
register_model_labels(
|
||||
"TaskHandover",
|
||||
{"en": "Task Handover", "fr": "Transfert de tâche"},
|
||||
{
|
||||
"taskId": {"en": "Task ID", "fr": "ID de la tâche"},
|
||||
"sourceTask": {"en": "Source Task", "fr": "Tâche source"},
|
||||
"inputDocuments": {"en": "Input Documents", "fr": "Documents d'entrée"},
|
||||
"outputDocuments": {"en": "Output Documents", "fr": "Documents de sortie"},
|
||||
"context": {"en": "Context", "fr": "Contexte"},
|
||||
"previousResults": {"en": "Previous Results", "fr": "Résultats précédents"},
|
||||
"improvements": {"en": "Improvements", "fr": "Améliorations"},
|
||||
"workflowSummary": {"en": "Workflow Summary", "fr": "Résumé du workflow"},
|
||||
"messageHistory": {"en": "Message History", "fr": "Historique des messages"},
|
||||
"timestamp": {"en": "Timestamp", "fr": "Horodatage"},
|
||||
"handoverType": {"en": "Handover Type", "fr": "Type de transfert"},
|
||||
},
|
||||
)
|
||||
|
||||
class TaskContext(BaseModel, ModelMixin):
|
||||
task_step: TaskStep
|
||||
workflow: Optional['ChatWorkflow'] = None
|
||||
workflow_id: Optional[str] = None
|
||||
available_documents: Optional[str] = "No documents available"
|
||||
available_connections: Optional[list[str]] = Field(default_factory=list)
|
||||
previous_results: Optional[list[str]] = Field(default_factory=list)
|
||||
previous_handover: Optional[TaskHandover] = None
|
||||
improvements: Optional[list[str]] = Field(default_factory=list)
|
||||
retry_count: Optional[int] = 0
|
||||
previous_action_results: Optional[list] = Field(default_factory=list)
|
||||
previous_review_result: Optional[dict] = None
|
||||
is_regeneration: Optional[bool] = False
|
||||
failure_patterns: Optional[list[str]] = Field(default_factory=list)
|
||||
failed_actions: Optional[list] = Field(default_factory=list)
|
||||
successful_actions: Optional[list] = Field(default_factory=list)
|
||||
criteria_progress: Optional[dict] = None
|
||||
|
||||
def getDocumentReferences(self) -> List[str]:
|
||||
docs = []
|
||||
if self.previous_handover:
|
||||
for doc_exchange in self.previous_handover.inputDocuments:
|
||||
docs.extend(doc_exchange.documents)
|
||||
return list(set(docs))
|
||||
|
||||
def addImprovement(self, improvement: str) -> None:
|
||||
if improvement not in (self.improvements or []):
|
||||
if self.improvements is None:
|
||||
self.improvements = []
|
||||
self.improvements.append(improvement)
|
||||
|
||||
class ReviewContext(BaseModel, ModelMixin):
|
||||
task_step: TaskStep
|
||||
task_actions: Optional[list] = Field(default_factory=list)
|
||||
action_results: Optional[list] = Field(default_factory=list)
|
||||
step_result: Optional[dict] = Field(default_factory=dict)
|
||||
workflow_id: Optional[str] = None
|
||||
previous_results: Optional[list[str]] = Field(default_factory=list)
|
||||
|
||||
class ReviewResult(BaseModel, ModelMixin):
|
||||
status: str
|
||||
reason: Optional[str] = None
|
||||
improvements: Optional[list[str]] = Field(default_factory=list)
|
||||
quality_score: Optional[int] = 5
|
||||
missing_outputs: Optional[list[str]] = Field(default_factory=list)
|
||||
met_criteria: Optional[list[str]] = Field(default_factory=list)
|
||||
unmet_criteria: Optional[list[str]] = Field(default_factory=list)
|
||||
confidence: Optional[float] = 0.5
|
||||
userMessage: Optional[str] = Field(None, description="User-friendly message in user's language")
|
||||
register_model_labels(
|
||||
"ReviewResult",
|
||||
{"en": "Review Result", "fr": "Résultat de l'évaluation"},
|
||||
{
|
||||
"status": {"en": "Status", "fr": "Statut"},
|
||||
"reason": {"en": "Reason", "fr": "Raison"},
|
||||
"improvements": {"en": "Improvements", "fr": "Améliorations"},
|
||||
"quality_score": {"en": "Quality Score", "fr": "Score de qualité"},
|
||||
"missing_outputs": {"en": "Missing Outputs", "fr": "Sorties manquantes"},
|
||||
"met_criteria": {"en": "Met Criteria", "fr": "Critères respectés"},
|
||||
"unmet_criteria": {"en": "Unmet Criteria", "fr": "Critères non respectés"},
|
||||
"confidence": {"en": "Confidence", "fr": "Confiance"},
|
||||
"userMessage": {"en": "User Message", "fr": "Message utilisateur"},
|
||||
},
|
||||
)
|
||||
|
||||
class TaskPlan(BaseModel, ModelMixin):
|
||||
overview: str
|
||||
tasks: list[TaskStep]
|
||||
userMessage: Optional[str] = Field(None, description="Overall user-friendly message for the task plan")
|
||||
register_model_labels(
|
||||
"TaskPlan",
|
||||
{"en": "Task Plan", "fr": "Plan de tâches"},
|
||||
{
|
||||
"overview": {"en": "Overview", "fr": "Aperçu"},
|
||||
"tasks": {"en": "Tasks", "fr": "Tâches"},
|
||||
"userMessage": {"en": "User Message", "fr": "Message utilisateur"},
|
||||
},
|
||||
)
|
||||
|
||||
# Resolve forward references
|
||||
TaskContext.update_forward_refs()
|
||||
|
||||
class PromptPlaceholder(BaseModel, ModelMixin):
|
||||
label: str
|
||||
content: str
|
||||
summaryAllowed: bool = Field(default=False, description="Whether host may summarize content before sending to AI")
|
||||
register_model_labels(
|
||||
"PromptPlaceholder",
|
||||
{"en": "Prompt Placeholder", "fr": "Espace réservé d'invite"},
|
||||
{
|
||||
"label": {"en": "Label", "fr": "Libellé"},
|
||||
"content": {"en": "Content", "fr": "Contenu"},
|
||||
"summaryAllowed": {"en": "Summary Allowed", "fr": "Résumé autorisé"},
|
||||
},
|
||||
)
|
||||
|
||||
class PromptBundle(BaseModel, ModelMixin):
|
||||
prompt: str
|
||||
placeholders: List[PromptPlaceholder] = Field(default_factory=list)
|
||||
register_model_labels(
|
||||
"PromptBundle", {"en": "Prompt Bundle", "fr": "Lot d'invite"},
|
||||
{
|
||||
"prompt": {"en": "Prompt", "fr": "Invite"},
|
||||
"placeholders": {"en": "Placeholders", "fr": "Espaces réservés"},
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class ContentPart(BaseModel):
|
|||
metadata: Dict[str, Any] = Field(default_factory=dict, description="Arbitrary metadata for the part")
|
||||
|
||||
|
||||
class ExtractedContent(BaseModel):
|
||||
class ContentExtracted(BaseModel):
|
||||
id: str = Field(description="Extraction id or source document id")
|
||||
parts: List[ContentPart] = Field(default_factory=list, description="List of extracted parts")
|
||||
summary: Optional[Dict[str, Any]] = Field(default=None, description="Optional extraction summary")
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ class FileItem(BaseModel, ModelMixin):
|
|||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
return super().to_dict()
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"FileItem",
|
||||
{"en": "File Item", "fr": "Élément de fichier"},
|
||||
|
|
@ -35,7 +33,6 @@ register_model_labels(
|
|||
},
|
||||
)
|
||||
|
||||
|
||||
class FilePreview(BaseModel, ModelMixin):
|
||||
content: Union[str, bytes] = Field(description="File content (text or binary)")
|
||||
mimeType: str = Field(description="MIME type of the file")
|
||||
|
|
@ -49,8 +46,6 @@ class FilePreview(BaseModel, ModelMixin):
|
|||
if isinstance(data.get("content"), bytes):
|
||||
data["content"] = base64.b64encode(data["content"]).decode("utf-8")
|
||||
return data
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"FilePreview",
|
||||
{"en": "File Preview", "fr": "Aperçu du fichier"},
|
||||
|
|
@ -64,13 +59,10 @@ register_model_labels(
|
|||
},
|
||||
)
|
||||
|
||||
|
||||
class FileData(BaseModel, ModelMixin):
|
||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key")
|
||||
data: str = Field(description="File data content")
|
||||
base64Encoded: bool = Field(description="Whether the data is base64 encoded")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"FileData",
|
||||
{"en": "File Data", "fr": "Données de fichier"},
|
||||
|
|
@ -80,5 +72,3 @@ register_model_labels(
|
|||
"base64Encoded": {"en": "Base64 Encoded", "fr": "Encodé en Base64"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ class DataNeutraliserConfig(BaseModel, ModelMixin):
|
|||
namesToParse: str = Field(default="", description="Multiline list of names to parse for neutralization", frontend_type="textarea", frontend_readonly=False, frontend_required=False)
|
||||
sharepointSourcePath: str = Field(default="", description="SharePoint path to read files for neutralization", frontend_type="text", frontend_readonly=False, frontend_required=False)
|
||||
sharepointTargetPath: str = Field(default="", description="SharePoint path to store neutralized files", frontend_type="text", frontend_readonly=False, frontend_required=False)
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"DataNeutraliserConfig",
|
||||
{"en": "Data Neutralization Config", "fr": "Configuration de neutralisation des données"},
|
||||
|
|
@ -30,7 +28,6 @@ register_model_labels(
|
|||
},
|
||||
)
|
||||
|
||||
|
||||
class DataNeutralizerAttributes(BaseModel, ModelMixin):
|
||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Unique ID of the attribute mapping (used as UID in neutralized files)", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||
mandateId: str = Field(description="ID of the mandate this attribute belongs to", frontend_type="text", frontend_readonly=True, frontend_required=True)
|
||||
|
|
@ -38,8 +35,6 @@ class DataNeutralizerAttributes(BaseModel, ModelMixin):
|
|||
originalText: str = Field(description="Original text that was neutralized", frontend_type="text", frontend_readonly=True, frontend_required=True)
|
||||
fileId: Optional[str] = Field(default=None, description="ID of the file this attribute belongs to", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||
patternType: str = Field(description="Type of pattern that matched (email, phone, name, etc.)", frontend_type="text", frontend_readonly=True, frontend_required=True)
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"DataNeutralizerAttributes",
|
||||
{"en": "Neutralized Data Attribute", "fr": "Attribut de données neutralisées"},
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ class TokenStatus(str, Enum):
|
|||
ACTIVE = "active"
|
||||
REVOKED = "revoked"
|
||||
|
||||
|
||||
class Token(BaseModel, ModelMixin):
|
||||
id: Optional[str] = None
|
||||
userId: str
|
||||
|
|
@ -33,8 +32,6 @@ class Token(BaseModel, ModelMixin):
|
|||
|
||||
class Config:
|
||||
use_enum_values = True
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"Token",
|
||||
{"en": "Token", "fr": "Jeton"},
|
||||
|
|
@ -57,7 +54,6 @@ register_model_labels(
|
|||
},
|
||||
)
|
||||
|
||||
|
||||
class AuthEvent(BaseModel, ModelMixin):
|
||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Unique ID of the auth event", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||
userId: str = Field(description="ID of the user this event belongs to", frontend_type="text", frontend_readonly=True, frontend_required=True)
|
||||
|
|
@ -67,8 +63,6 @@ class AuthEvent(BaseModel, ModelMixin):
|
|||
userAgent: Optional[str] = Field(default=None, description="User agent string from the request", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||
success: bool = Field(default=True, description="Whether the authentication event was successful", frontend_type="boolean", frontend_readonly=True, frontend_required=True)
|
||||
details: Optional[str] = Field(default=None, description="Additional details about the event", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"AuthEvent",
|
||||
{"en": "Authentication Event", "fr": "Événement d'authentification"},
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ class TicketFieldAttribute(BaseModel):
|
|||
fieldName: str = Field(description="Human-readable field name")
|
||||
field: str = Field(description="Ticket field ID/key")
|
||||
|
||||
|
||||
class TicketBase(ABC):
|
||||
@abstractmethod
|
||||
async def read_attributes(self) -> list[TicketFieldAttribute]: ...
|
||||
|
|
|
|||
|
|
@ -13,20 +13,17 @@ class AuthAuthority(str, Enum):
|
|||
GOOGLE = "google"
|
||||
MSFT = "msft"
|
||||
|
||||
|
||||
class UserPrivilege(str, Enum):
|
||||
SYSADMIN = "sysadmin"
|
||||
ADMIN = "admin"
|
||||
USER = "user"
|
||||
|
||||
|
||||
class ConnectionStatus(str, Enum):
|
||||
ACTIVE = "active"
|
||||
EXPIRED = "expired"
|
||||
REVOKED = "revoked"
|
||||
PENDING = "pending"
|
||||
|
||||
|
||||
class Mandate(BaseModel, ModelMixin):
|
||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Unique ID of the mandate", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||
name: str = Field(description="Name of the mandate", frontend_type="text", frontend_readonly=False, frontend_required=True)
|
||||
|
|
@ -37,8 +34,6 @@ class Mandate(BaseModel, ModelMixin):
|
|||
{"value": "it", "label": {"en": "Italiano", "fr": "Italien"}},
|
||||
])
|
||||
enabled: bool = Field(default=True, description="Indicates whether the mandate is enabled", frontend_type="checkbox", frontend_readonly=False, frontend_required=False)
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"Mandate",
|
||||
{"en": "Mandate", "fr": "Mandat"},
|
||||
|
|
@ -50,7 +45,6 @@ register_model_labels(
|
|||
},
|
||||
)
|
||||
|
||||
|
||||
class UserConnection(BaseModel, ModelMixin):
|
||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Unique ID of the connection", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||
userId: str = Field(description="ID of the user this connection belongs to", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||
|
|
@ -77,8 +71,6 @@ class UserConnection(BaseModel, ModelMixin):
|
|||
{"value": "none", "label": {"en": "None", "fr": "Aucun"}},
|
||||
])
|
||||
tokenExpiresAt: Optional[float] = Field(None, description="When the current token expires (UTC timestamp in seconds)", frontend_type="timestamp", frontend_readonly=True, frontend_required=False)
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"UserConnection",
|
||||
{"en": "User Connection", "fr": "Connexion utilisateur"},
|
||||
|
|
@ -98,7 +90,6 @@ register_model_labels(
|
|||
},
|
||||
)
|
||||
|
||||
|
||||
class User(BaseModel, ModelMixin):
|
||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Unique ID of the user", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||
username: str = Field(description="Username for login", frontend_type="text", frontend_readonly=False, frontend_required=True)
|
||||
|
|
@ -122,8 +113,6 @@ class User(BaseModel, ModelMixin):
|
|||
{"value": "msft", "label": {"en": "Microsoft", "fr": "Microsoft"}},
|
||||
])
|
||||
mandateId: Optional[str] = Field(None, description="ID of the mandate this user belongs to", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"User",
|
||||
{"en": "User", "fr": "Utilisateur"},
|
||||
|
|
@ -140,15 +129,10 @@ register_model_labels(
|
|||
},
|
||||
)
|
||||
|
||||
|
||||
class UserInDB(User):
|
||||
hashedPassword: Optional[str] = Field(None, description="Hash of the user password")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"UserInDB",
|
||||
{"en": "User Access", "fr": "Accès de l'utilisateur"},
|
||||
{"hashedPassword": {"en": "Password hash", "fr": "Hachage de mot de passe"}},
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ class Prompt(BaseModel, ModelMixin):
|
|||
mandateId: str = Field(description="ID of the mandate this prompt belongs to", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||
content: str = Field(description="Content of the prompt", frontend_type="textarea", frontend_readonly=False, frontend_required=True)
|
||||
name: str = Field(description="Name of the prompt", frontend_type="text", frontend_readonly=False, frontend_required=True)
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"Prompt",
|
||||
{"en": "Prompt", "fr": "Invite"},
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ class VoiceSettings(BaseModel, ModelMixin):
|
|||
def to_dict(self) -> Dict[str, Any]:
|
||||
return super().to_dict()
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"VoiceSettings",
|
||||
{"en": "Voice Settings", "fr": "Paramètres vocaux"},
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
"""Web-related modules"""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from pydantic import BaseModel, Field, HttpUrl
|
||||
from typing import List, Optional, Literal, Dict, Any
|
||||
from modules.shared.configuration import APP_CONFIG
|
||||
from modules.datamodels.datamodelWorkflow import ActionDocument, ActionResult
|
||||
from modules.datamodels.datamodelChat import ActionDocument, ActionResult
|
||||
|
||||
|
||||
WEB_SEARCH_MAX_QUERY_LENGTH: int = int(APP_CONFIG.get("Web_Search_MAX_QUERY_LENGTH", "400"))
|
||||
|
|
@ -27,7 +25,6 @@ class WebResearchOptions(BaseModel):
|
|||
include_answer: Optional[bool] = Field(default=None, description="Include AI answer")
|
||||
include_raw_content: Optional[bool] = Field(default=None, description="Include raw content")
|
||||
|
||||
|
||||
class WebResearchRequest(BaseModel):
|
||||
"""Main web research request"""
|
||||
user_prompt: str = Field(min_length=1, max_length=WEB_SEARCH_MAX_QUERY_LENGTH, description="User's research question or prompt")
|
||||
|
|
@ -35,20 +32,17 @@ class WebResearchRequest(BaseModel):
|
|||
max_results: int = Field(default=5, ge=1, le=WEB_SEARCH_MAX_RESULTS, description="Max search results")
|
||||
options: WebResearchOptions = Field(default_factory=WebResearchOptions, description="Advanced options")
|
||||
|
||||
|
||||
class WebSearchResultItem(BaseModel):
|
||||
"""Individual search result"""
|
||||
title: str
|
||||
url: HttpUrl
|
||||
raw_content: Optional[str] = Field(default=None, description="Raw HTML content")
|
||||
|
||||
|
||||
class WebCrawlResultItem(BaseModel):
|
||||
"""Individual crawl result"""
|
||||
url: HttpUrl
|
||||
content: str
|
||||
|
||||
|
||||
class WebResearchDocumentData(BaseModel):
|
||||
"""Complete web research results"""
|
||||
user_prompt: str
|
||||
|
|
@ -60,21 +54,14 @@ class WebResearchDocumentData(BaseModel):
|
|||
individual_content: Optional[Dict[str, str]] = None # URL -> content mapping
|
||||
debug_info: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
class WebResearchActionDocument(ActionDocument):
|
||||
documentData: WebResearchDocumentData
|
||||
|
||||
|
||||
class WebResearchActionResult(ActionResult):
|
||||
documents: List[WebResearchActionDocument] = Field(default_factory=list)
|
||||
|
||||
|
||||
class WebResearchBase(ABC):
|
||||
@abstractmethod
|
||||
async def web_research(self, request: WebResearchRequest) -> WebResearchActionResult: ...
|
||||
|
||||
|
||||
# Legacy models for connector compatibility
|
||||
|
||||
class WebSearchDocumentData(BaseModel):
|
||||
"""Search results document data"""
|
||||
query: str
|
||||
|
|
@ -153,5 +140,3 @@ class WebScrapeResultItem(BaseModel):
|
|||
"""Individual scrape result"""
|
||||
url: HttpUrl
|
||||
content: str
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,446 +0,0 @@
|
|||
"""Workflow-related base datamodels and step/task structures."""
|
||||
|
||||
from typing import List, Dict, Any, Optional
|
||||
from pydantic import BaseModel, Field
|
||||
from modules.shared.attributeUtils import register_model_labels, ModelMixin
|
||||
|
||||
|
||||
class ActionDocument(BaseModel, ModelMixin):
|
||||
"""Clear document structure for action results"""
|
||||
documentName: str = Field(description="Name of the document")
|
||||
documentData: Any = Field(description="Content/data of the document")
|
||||
mimeType: str = Field(description="MIME type of the document")
|
||||
register_model_labels(
|
||||
"ActionDocument",
|
||||
{"en": "Action Document", "fr": "Document d'action"},
|
||||
{
|
||||
"documentName": {"en": "Document Name", "fr": "Nom du document"},
|
||||
"documentData": {"en": "Document Data", "fr": "Données du document"},
|
||||
"mimeType": {"en": "MIME Type", "fr": "Type MIME"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class ActionResult(BaseModel, ModelMixin):
|
||||
"""Clean action result with documents as primary output
|
||||
|
||||
IMPORTANT: Action methods should NOT set resultLabel in their return value.
|
||||
The resultLabel is managed by the action handler using the action's execResultLabel
|
||||
from the action plan. This ensures consistent document routing throughout the workflow.
|
||||
"""
|
||||
|
||||
success: bool = Field(description="Whether execution succeeded")
|
||||
error: Optional[str] = Field(None, description="Error message if failed")
|
||||
documents: List[ActionDocument] = Field(default_factory=list, description="Document outputs")
|
||||
resultLabel: Optional[str] = Field(None, description="Label for document routing (set by action handler, not by action methods)")
|
||||
|
||||
@classmethod
|
||||
def isSuccess(cls, documents: List[ActionDocument] = None) -> "ActionResult":
|
||||
return cls(success=True, documents=documents or [])
|
||||
|
||||
@classmethod
|
||||
def isFailure(cls, error: str, documents: List[ActionDocument] = None) -> "ActionResult":
|
||||
return cls(success=False, documents=documents or [], error=error)
|
||||
register_model_labels(
|
||||
"ActionResult",
|
||||
{"en": "Action Result", "fr": "Résultat de l'action"},
|
||||
{
|
||||
"success": {"en": "Success", "fr": "Succès"},
|
||||
"error": {"en": "Error", "fr": "Erreur"},
|
||||
"documents": {"en": "Documents", "fr": "Documents"},
|
||||
"resultLabel": {"en": "Result Label", "fr": "Étiquette du résultat"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class ActionSelection(BaseModel, ModelMixin):
|
||||
method: str = Field(description="Method to execute (e.g., web, document, ai)")
|
||||
name: str = Field(description="Action name within the method (e.g., search, extract)")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"ActionSelection",
|
||||
{"en": "Action Selection", "fr": "Sélection d'action"},
|
||||
{
|
||||
"method": {"en": "Method", "fr": "Méthode"},
|
||||
"name": {"en": "Action Name", "fr": "Nom de l'action"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class ActionParameters(BaseModel, ModelMixin):
|
||||
parameters: Dict[str, Any] = Field(default_factory=dict, description="Parameters to execute the selected action")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"ActionParameters",
|
||||
{"en": "Action Parameters", "fr": "Paramètres d'action"},
|
||||
{
|
||||
"parameters": {"en": "Parameters", "fr": "Paramètres"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class ObservationPreview(BaseModel, ModelMixin):
|
||||
name: str = Field(description="Document name or URL label")
|
||||
mime: str = Field(description="MIME type or kind")
|
||||
snippet: str = Field(description="Short snippet or summary")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"ObservationPreview",
|
||||
{"en": "Observation Preview", "fr": "Aperçu d'observation"},
|
||||
{
|
||||
"name": {"en": "Name", "fr": "Nom"},
|
||||
"mime": {"en": "MIME", "fr": "MIME"},
|
||||
"snippet": {"en": "Snippet", "fr": "Extrait"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class Observation(BaseModel, ModelMixin):
|
||||
success: bool = Field(description="Action execution success flag")
|
||||
resultLabel: str = Field(description="Deterministic label for produced documents")
|
||||
documentsCount: int = Field(description="Number of produced documents")
|
||||
previews: List[ObservationPreview] = Field(default_factory=list, description="Compact previews of outputs")
|
||||
notes: List[str] = Field(default_factory=list, description="Short notes or key facts")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"Observation",
|
||||
{"en": "Observation", "fr": "Observation"},
|
||||
{
|
||||
"success": {"en": "Success", "fr": "Succès"},
|
||||
"resultLabel": {"en": "Result Label", "fr": "Étiquette du résultat"},
|
||||
"documentsCount": {"en": "Documents Count", "fr": "Nombre de documents"},
|
||||
"previews": {"en": "Previews", "fr": "Aperçus"},
|
||||
"notes": {"en": "Notes", "fr": "Notes"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class TaskStatus(str):
|
||||
PENDING = "pending"
|
||||
RUNNING = "running"
|
||||
COMPLETED = "completed"
|
||||
FAILED = "failed"
|
||||
CANCELLED = "cancelled"
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"TaskStatus",
|
||||
{"en": "Task Status", "fr": "Statut de la tâche"},
|
||||
{
|
||||
"PENDING": {"en": "Pending", "fr": "En attente"},
|
||||
"RUNNING": {"en": "Running", "fr": "En cours"},
|
||||
"COMPLETED": {"en": "Completed", "fr": "Terminé"},
|
||||
"FAILED": {"en": "Failed", "fr": "Échec"},
|
||||
"CANCELLED": {"en": "Cancelled", "fr": "Annulé"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class DocumentExchange(BaseModel, ModelMixin):
|
||||
documentsLabel: str = Field(description="Label for the set of documents")
|
||||
documents: List[str] = Field(default_factory=list, description="List of document references")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"DocumentExchange",
|
||||
{"en": "Document Exchange", "fr": "Échange de documents"},
|
||||
{
|
||||
"documentsLabel": {"en": "Documents Label", "fr": "Label des documents"},
|
||||
"documents": {"en": "Documents", "fr": "Documents"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class TaskAction(BaseModel, ModelMixin):
|
||||
id: str = Field(..., description="Action ID")
|
||||
execMethod: str = Field(..., description="Method to execute")
|
||||
execAction: str = Field(..., description="Action to perform")
|
||||
execParameters: Dict[str, Any] = Field(default_factory=dict, description="Action parameters")
|
||||
execResultLabel: Optional[str] = Field(None, description="Label for the set of result documents")
|
||||
expectedDocumentFormats: Optional[List[Dict[str, str]]] = Field(None, description="Expected document formats (optional)")
|
||||
userMessage: Optional[str] = Field(None, description="User-friendly message in user's language")
|
||||
status: TaskStatus = Field(default=TaskStatus.PENDING, description="Action status")
|
||||
error: Optional[str] = Field(None, description="Error message if action failed")
|
||||
retryCount: int = Field(default=0, description="Number of retries attempted")
|
||||
retryMax: int = Field(default=3, description="Maximum number of retries")
|
||||
processingTime: Optional[float] = Field(None, description="Processing time in seconds")
|
||||
timestamp: float = Field(..., description="When the action was executed (UTC timestamp in seconds)")
|
||||
result: Optional[str] = Field(None, description="Result of the action")
|
||||
|
||||
def setSuccess(self, result: str = None) -> None:
|
||||
"""Set the action as successful with optional result"""
|
||||
self.status = TaskStatus.COMPLETED
|
||||
self.error = None
|
||||
if result is not None:
|
||||
self.result = result
|
||||
|
||||
def setError(self, error_message: str) -> None:
|
||||
"""Set the action as failed with error message"""
|
||||
self.status = TaskStatus.FAILED
|
||||
self.error = error_message
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"TaskAction",
|
||||
{"en": "Task Action", "fr": "Action de tâche"},
|
||||
{
|
||||
"id": {"en": "Action ID", "fr": "ID de l'action"},
|
||||
"execMethod": {"en": "Method", "fr": "Méthode"},
|
||||
"execAction": {"en": "Action", "fr": "Action"},
|
||||
"execParameters": {"en": "Parameters", "fr": "Paramètres"},
|
||||
"execResultLabel": {"en": "Result Label", "fr": "Label du résultat"},
|
||||
"expectedDocumentFormats": {"en": "Expected Document Formats", "fr": "Formats de documents attendus"},
|
||||
"userMessage": {"en": "User Message", "fr": "Message utilisateur"},
|
||||
"status": {"en": "Status", "fr": "Statut"},
|
||||
"error": {"en": "Error", "fr": "Erreur"},
|
||||
"retryCount": {"en": "Retry Count", "fr": "Nombre de tentatives"},
|
||||
"retryMax": {"en": "Max Retries", "fr": "Tentatives max"},
|
||||
"processingTime": {"en": "Processing Time", "fr": "Temps de traitement"},
|
||||
"timestamp": {"en": "Timestamp", "fr": "Horodatage"},
|
||||
"result": {"en": "Result", "fr": "Résultat"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class TaskResult(BaseModel, ModelMixin):
|
||||
taskId: str = Field(..., description="Task ID")
|
||||
status: TaskStatus = Field(default=TaskStatus.PENDING, description="Task status")
|
||||
success: bool = Field(..., description="Whether the task was successful")
|
||||
feedback: Optional[str] = Field(None, description="Task feedback message")
|
||||
error: Optional[str] = Field(None, description="Error message if task failed")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"TaskResult",
|
||||
{"en": "Task Result", "fr": "Résultat de tâche"},
|
||||
{
|
||||
"taskId": {"en": "Task ID", "fr": "ID de la tâche"},
|
||||
"status": {"en": "Status", "fr": "Statut"},
|
||||
"success": {"en": "Success", "fr": "Succès"},
|
||||
"feedback": {"en": "Feedback", "fr": "Retour"},
|
||||
"error": {"en": "Error", "fr": "Erreur"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class TaskItem(BaseModel, ModelMixin):
|
||||
id: str = Field(..., description="Task ID")
|
||||
workflowId: str = Field(..., description="Workflow ID")
|
||||
userInput: str = Field(..., description="User input that triggered the task")
|
||||
status: TaskStatus = Field(default=TaskStatus.PENDING, description="Task status")
|
||||
error: Optional[str] = Field(None, description="Error message if task failed")
|
||||
startedAt: Optional[float] = Field(None, description="When the task started (UTC timestamp in seconds)")
|
||||
finishedAt: Optional[float] = Field(None, description="When the task finished (UTC timestamp in seconds)")
|
||||
actionList: List[TaskAction] = Field(default_factory=list, description="List of actions to execute")
|
||||
retryCount: int = Field(default=0, description="Number of retries attempted")
|
||||
retryMax: int = Field(default=3, description="Maximum number of retries")
|
||||
rollbackOnFailure: bool = Field(default=True, description="Whether to rollback on failure")
|
||||
dependencies: List[str] = Field(default_factory=list, description="List of task IDs this task depends on")
|
||||
feedback: Optional[str] = Field(None, description="Task feedback message")
|
||||
processingTime: Optional[float] = Field(None, description="Total processing time in seconds")
|
||||
resultLabels: Optional[Dict[str, Any]] = Field(default_factory=dict, description="Map of result labels to their values")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"TaskItem",
|
||||
{"en": "Task", "fr": "Tâche"},
|
||||
{
|
||||
"id": {"en": "Task ID", "fr": "ID de la tâche"},
|
||||
"workflowId": {"en": "Workflow ID", "fr": "ID du workflow"},
|
||||
"userInput": {"en": "User Input", "fr": "Entrée utilisateur"},
|
||||
"status": {"en": "Status", "fr": "Statut"},
|
||||
"error": {"en": "Error", "fr": "Erreur"},
|
||||
"startedAt": {"en": "Started At", "fr": "Démarré à"},
|
||||
"finishedAt": {"en": "Finished At", "fr": "Terminé à"},
|
||||
"actionList": {"en": "Actions", "fr": "Actions"},
|
||||
"retryCount": {"en": "Retry Count", "fr": "Nombre de tentatives"},
|
||||
"retryMax": {"en": "Max Retries", "fr": "Tentatives max"},
|
||||
"processingTime": {"en": "Processing Time", "fr": "Temps de traitement"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class TaskStep(BaseModel, ModelMixin):
|
||||
id: str
|
||||
objective: str
|
||||
dependencies: Optional[list[str]] = Field(default_factory=list)
|
||||
success_criteria: Optional[list[str]] = Field(default_factory=list)
|
||||
estimated_complexity: Optional[str] = None
|
||||
userMessage: Optional[str] = Field(None, description="User-friendly message in user's language")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"TaskStep",
|
||||
{"en": "Task Step", "fr": "Étape de tâche"},
|
||||
{
|
||||
"id": {"en": "ID", "fr": "ID"},
|
||||
"objective": {"en": "Objective", "fr": "Objectif"},
|
||||
"dependencies": {"en": "Dependencies", "fr": "Dépendances"},
|
||||
"success_criteria": {"en": "Success Criteria", "fr": "Critères de succès"},
|
||||
"estimated_complexity": {"en": "Estimated Complexity", "fr": "Complexité estimée"},
|
||||
"userMessage": {"en": "User Message", "fr": "Message utilisateur"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class TaskHandover(BaseModel, ModelMixin):
|
||||
taskId: str = Field(description="Target task ID")
|
||||
sourceTask: Optional[str] = Field(None, description="Source task ID")
|
||||
inputDocuments: List[DocumentExchange] = Field(default_factory=list, description="Available input documents")
|
||||
outputDocuments: List[DocumentExchange] = Field(default_factory=list, description="Produced output documents")
|
||||
context: Dict[str, Any] = Field(default_factory=dict, description="Task context")
|
||||
previousResults: List[str] = Field(default_factory=list, description="Previous result summaries")
|
||||
improvements: List[str] = Field(default_factory=list, description="Improvement suggestions")
|
||||
workflowSummary: Optional[str] = Field(None, description="Summarized workflow context")
|
||||
messageHistory: List[str] = Field(default_factory=list, description="Key message summaries")
|
||||
timestamp: float = Field(..., description="When the handover was created (UTC timestamp in seconds)")
|
||||
handoverType: str = Field(default="task", description="Type of handover: task, phase, or workflow")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"TaskHandover",
|
||||
{"en": "Task Handover", "fr": "Transfert de tâche"},
|
||||
{
|
||||
"taskId": {"en": "Task ID", "fr": "ID de la tâche"},
|
||||
"sourceTask": {"en": "Source Task", "fr": "Tâche source"},
|
||||
"inputDocuments": {"en": "Input Documents", "fr": "Documents d'entrée"},
|
||||
"outputDocuments": {"en": "Output Documents", "fr": "Documents de sortie"},
|
||||
"context": {"en": "Context", "fr": "Contexte"},
|
||||
"previousResults": {"en": "Previous Results", "fr": "Résultats précédents"},
|
||||
"improvements": {"en": "Improvements", "fr": "Améliorations"},
|
||||
"workflowSummary": {"en": "Workflow Summary", "fr": "Résumé du workflow"},
|
||||
"messageHistory": {"en": "Message History", "fr": "Historique des messages"},
|
||||
"timestamp": {"en": "Timestamp", "fr": "Horodatage"},
|
||||
"handoverType": {"en": "Handover Type", "fr": "Type de transfert"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class TaskContext(BaseModel, ModelMixin):
|
||||
task_step: TaskStep
|
||||
workflow: Optional['ChatWorkflow'] = None
|
||||
workflow_id: Optional[str] = None
|
||||
available_documents: Optional[str] = "No documents available"
|
||||
available_connections: Optional[list[str]] = Field(default_factory=list)
|
||||
previous_results: Optional[list[str]] = Field(default_factory=list)
|
||||
previous_handover: Optional[TaskHandover] = None
|
||||
improvements: Optional[list[str]] = Field(default_factory=list)
|
||||
retry_count: Optional[int] = 0
|
||||
previous_action_results: Optional[list] = Field(default_factory=list)
|
||||
previous_review_result: Optional[dict] = None
|
||||
is_regeneration: Optional[bool] = False
|
||||
failure_patterns: Optional[list[str]] = Field(default_factory=list)
|
||||
failed_actions: Optional[list] = Field(default_factory=list)
|
||||
successful_actions: Optional[list] = Field(default_factory=list)
|
||||
criteria_progress: Optional[dict] = None
|
||||
|
||||
def getDocumentReferences(self) -> List[str]:
|
||||
docs = []
|
||||
if self.previous_handover:
|
||||
for doc_exchange in self.previous_handover.inputDocuments:
|
||||
docs.extend(doc_exchange.documents)
|
||||
return list(set(docs))
|
||||
|
||||
def addImprovement(self, improvement: str) -> None:
|
||||
if improvement not in (self.improvements or []):
|
||||
if self.improvements is None:
|
||||
self.improvements = []
|
||||
self.improvements.append(improvement)
|
||||
|
||||
|
||||
class ReviewContext(BaseModel, ModelMixin):
|
||||
task_step: TaskStep
|
||||
task_actions: Optional[list] = Field(default_factory=list)
|
||||
action_results: Optional[list] = Field(default_factory=list)
|
||||
step_result: Optional[dict] = Field(default_factory=dict)
|
||||
workflow_id: Optional[str] = None
|
||||
previous_results: Optional[list[str]] = Field(default_factory=list)
|
||||
|
||||
|
||||
class ReviewResult(BaseModel, ModelMixin):
|
||||
status: str
|
||||
reason: Optional[str] = None
|
||||
improvements: Optional[list[str]] = Field(default_factory=list)
|
||||
quality_score: Optional[int] = 5
|
||||
missing_outputs: Optional[list[str]] = Field(default_factory=list)
|
||||
met_criteria: Optional[list[str]] = Field(default_factory=list)
|
||||
unmet_criteria: Optional[list[str]] = Field(default_factory=list)
|
||||
confidence: Optional[float] = 0.5
|
||||
userMessage: Optional[str] = Field(None, description="User-friendly message in user's language")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"ReviewResult",
|
||||
{"en": "Review Result", "fr": "Résultat de l'évaluation"},
|
||||
{
|
||||
"status": {"en": "Status", "fr": "Statut"},
|
||||
"reason": {"en": "Reason", "fr": "Raison"},
|
||||
"improvements": {"en": "Improvements", "fr": "Améliorations"},
|
||||
"quality_score": {"en": "Quality Score", "fr": "Score de qualité"},
|
||||
"missing_outputs": {"en": "Missing Outputs", "fr": "Sorties manquantes"},
|
||||
"met_criteria": {"en": "Met Criteria", "fr": "Critères respectés"},
|
||||
"unmet_criteria": {"en": "Unmet Criteria", "fr": "Critères non respectés"},
|
||||
"confidence": {"en": "Confidence", "fr": "Confiance"},
|
||||
"userMessage": {"en": "User Message", "fr": "Message utilisateur"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class TaskPlan(BaseModel, ModelMixin):
|
||||
overview: str
|
||||
tasks: list[TaskStep]
|
||||
userMessage: Optional[str] = Field(None, description="Overall user-friendly message for the task plan")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"TaskPlan",
|
||||
{"en": "Task Plan", "fr": "Plan de tâches"},
|
||||
{
|
||||
"overview": {"en": "Overview", "fr": "Aperçu"},
|
||||
"tasks": {"en": "Tasks", "fr": "Tâches"},
|
||||
"userMessage": {"en": "User Message", "fr": "Message utilisateur"},
|
||||
},
|
||||
)
|
||||
|
||||
# Resolve forward references
|
||||
from modules.datamodels.datamodelChat import ChatWorkflow
|
||||
TaskContext.update_forward_refs()
|
||||
|
||||
# -----------------------------
|
||||
# Prompt helper datamodels
|
||||
# -----------------------------
|
||||
|
||||
class PromptPlaceholder(BaseModel, ModelMixin):
|
||||
label: str
|
||||
content: str
|
||||
summaryAllowed: bool = Field(default=False, description="Whether host may summarize content before sending to AI")
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"PromptPlaceholder",
|
||||
{"en": "Prompt Placeholder", "fr": "Espace réservé d'invite"},
|
||||
{
|
||||
"label": {"en": "Label", "fr": "Libellé"},
|
||||
"content": {"en": "Content", "fr": "Contenu"},
|
||||
"summaryAllowed": {"en": "Summary Allowed", "fr": "Résumé autorisé"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class PromptBundle(BaseModel, ModelMixin):
|
||||
prompt: str
|
||||
placeholders: List[PromptPlaceholder] = Field(default_factory=list)
|
||||
|
||||
|
||||
register_model_labels(
|
||||
"PromptBundle",
|
||||
{"en": "Prompt Bundle", "fr": "Lot d'invite"},
|
||||
{
|
||||
"prompt": {"en": "Prompt", "fr": "Invite"},
|
||||
"placeholders": {"en": "Placeholders", "fr": "Espaces réservés"},
|
||||
},
|
||||
)
|
||||
|
|
@ -27,7 +27,7 @@ from modules.datamodels.datamodelWeb import (
|
|||
WebSearchRequest,
|
||||
WebCrawlRequest,
|
||||
)
|
||||
from modules.datamodels.datamodelWorkflow import ActionDocument
|
||||
from modules.datamodels.datamodelChat import ActionDocument
|
||||
|
||||
|
||||
# Comprehensive model registry with capability tags and function mapping
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ from typing import Dict, Any, List, Optional, Union, get_origin, get_args
|
|||
import asyncio
|
||||
|
||||
from modules.interfaces.interfaceDbChatAccess import ChatAccess
|
||||
from modules.datamodels.datamodelWorkflow import (
|
||||
TaskAction,
|
||||
from modules.datamodels.datamodelChat import (
|
||||
ActionItem,
|
||||
TaskResult,
|
||||
TaskItem,
|
||||
TaskStatus,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import logging
|
||||
from typing import Dict, Any, List, Optional, Tuple, Union
|
||||
from modules.datamodels.datamodelWorkflow import PromptPlaceholder
|
||||
from modules.datamodels.datamodelChat import PromptPlaceholder
|
||||
|
||||
from modules.datamodels.datamodelChat import ChatDocument
|
||||
from modules.services.serviceExtraction.mainServiceExtraction import ExtractionService
|
||||
|
|
@ -909,7 +909,7 @@ class AiService:
|
|||
|
||||
logger.info(f"Extraction completed: {len(extracted_content)} documents")
|
||||
|
||||
# Build context from list of ExtractedContent
|
||||
# Build context from list of extracted content
|
||||
if isinstance(extracted_content, list):
|
||||
context_parts = []
|
||||
chunk_count = 0
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import logging
|
|||
|
||||
from .subRegistry import ExtractorRegistry, ChunkerRegistry
|
||||
from .subPipeline import runExtraction, poolAndLimit, applyAiIfRequested
|
||||
from modules.datamodels.datamodelExtraction import ExtractedContent, ContentPart, MergeStrategy
|
||||
from modules.datamodels.datamodelExtraction import ContentExtracted, ContentPart, MergeStrategy
|
||||
from modules.datamodels.datamodelChat import ChatDocument
|
||||
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ class ExtractionService:
|
|||
self._extractorRegistry = ExtractorRegistry()
|
||||
self._chunkerRegistry = ChunkerRegistry()
|
||||
|
||||
def extractContent(self, documents: List[ChatDocument], options: Dict[str, Any]) -> List[ExtractedContent]:
|
||||
def extractContent(self, documents: List[ChatDocument], options: Dict[str, Any]) -> List[ContentExtracted]:
|
||||
"""
|
||||
Extract content from a list of ChatDocument objects.
|
||||
|
||||
|
|
@ -26,9 +26,9 @@ class ExtractionService:
|
|||
options: Extraction options including maxSize, chunkAllowed, mergeStrategy, etc.
|
||||
|
||||
Returns:
|
||||
List of ExtractedContent objects, one per input document
|
||||
List of ContentExtracted objects, one per input document
|
||||
"""
|
||||
results: List[ExtractedContent] = []
|
||||
results: List[ContentExtracted] = []
|
||||
|
||||
# Lazy import to avoid circular deps and heavy init at module import
|
||||
from modules.interfaces.interfaceDbComponentObjects import getInterface
|
||||
|
|
@ -90,20 +90,20 @@ class ExtractionService:
|
|||
|
||||
def mergeAiResults(
|
||||
self,
|
||||
extractedContent: List[ExtractedContent],
|
||||
extractedContent: List[ContentExtracted],
|
||||
aiResults: List[str],
|
||||
strategy: MergeStrategy
|
||||
) -> ExtractedContent:
|
||||
) -> ContentExtracted:
|
||||
"""
|
||||
Merge AI results from chunked content back into a single ExtractedContent.
|
||||
Merge AI results from chunked content back into a single ContentExtracted.
|
||||
|
||||
Args:
|
||||
extractedContent: List of ExtractedContent objects that were processed
|
||||
extractedContent: List of ContentExtracted objects that were processed
|
||||
aiResults: List of AI response strings, one per chunk
|
||||
strategy: Merge strategy configuration (dict or MergeStrategy object)
|
||||
|
||||
Returns:
|
||||
Single ExtractedContent with merged AI results
|
||||
Single ContentExtracted with merged AI results
|
||||
"""
|
||||
logger.debug(f"=== MERGING AI RESULTS ===")
|
||||
logger.debug(f"Extracted content: {len(extractedContent)} documents")
|
||||
|
|
@ -150,8 +150,8 @@ class ExtractionService:
|
|||
# Default to concatenate
|
||||
mergedParts = self._mergeConcatenate(allParts, aiResultParts, mergeStrategy)
|
||||
|
||||
# Create final ExtractedContent
|
||||
mergedContent = ExtractedContent(
|
||||
# Create final ContentExtracted
|
||||
mergedContent = ContentExtracted(
|
||||
id=f"merged_{uuid.uuid4()}",
|
||||
parts=mergedParts
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from typing import Any, Dict, List
|
|||
import logging
|
||||
import os
|
||||
|
||||
from modules.datamodels.datamodelExtraction import ExtractedContent, ContentPart
|
||||
from modules.datamodels.datamodelExtraction import ContentExtracted, ContentPart
|
||||
from .subUtils import makeId
|
||||
from .subRegistry import ExtractorRegistry, ChunkerRegistry
|
||||
from .merging.text_merger import TextMerger
|
||||
|
|
@ -55,7 +55,7 @@ def _mergeParts(parts: List[ContentPart], mergeStrategy: Dict[str, Any]) -> List
|
|||
return merged_parts
|
||||
|
||||
|
||||
def runExtraction(extractorRegistry: ExtractorRegistry, chunkerRegistry: ChunkerRegistry, documentBytes: bytes, fileName: str, mimeType: str, options: Dict[str, Any]) -> ExtractedContent:
|
||||
def runExtraction(extractorRegistry: ExtractorRegistry, chunkerRegistry: ChunkerRegistry, documentBytes: bytes, fileName: str, mimeType: str, options: Dict[str, Any]) -> ContentExtracted:
|
||||
extractor = extractorRegistry.resolve(mimeType, fileName)
|
||||
if extractor is None:
|
||||
# fallback: single binary part
|
||||
|
|
@ -68,7 +68,7 @@ def runExtraction(extractorRegistry: ExtractorRegistry, chunkerRegistry: Chunker
|
|||
data="",
|
||||
metadata={"warning": "No extractor registered"}
|
||||
)
|
||||
return ExtractedContent(id=makeId(), parts=[part])
|
||||
return ContentExtracted(id=makeId(), parts=[part])
|
||||
|
||||
parts = extractor.extract(documentBytes, {"fileName": fileName, "mimeType": mimeType, "options": options})
|
||||
|
||||
|
|
@ -119,7 +119,7 @@ def runExtraction(extractorRegistry: ExtractorRegistry, chunkerRegistry: Chunker
|
|||
except Exception as _e:
|
||||
logger.debug(f"Debug dump skipped: {_e}")
|
||||
|
||||
return ExtractedContent(id=makeId(), parts=parts)
|
||||
return ContentExtracted(id=makeId(), parts=parts)
|
||||
|
||||
|
||||
def poolAndLimit(parts: List[ContentPart], chunkerRegistry: ChunkerRegistry, options: Dict[str, Any]) -> List[ContentPart]:
|
||||
|
|
@ -268,7 +268,7 @@ def _applySizeLimit(parts: List[ContentPart], maxSize: int) -> List[ContentPart]
|
|||
return kept
|
||||
|
||||
|
||||
def applyAiIfRequested(extracted: ExtractedContent, options: Dict[str, Any]) -> ExtractedContent:
|
||||
def applyAiIfRequested(extracted: ContentExtracted, options: Dict[str, Any]) -> ContentExtracted:
|
||||
"""
|
||||
Apply AI processing if requested in options.
|
||||
This is a placeholder for actual AI integration.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import uuid
|
|||
from typing import Dict, Any, List, Optional
|
||||
from modules.datamodels.datamodelUam import User, UserConnection
|
||||
from modules.datamodels.datamodelChat import ChatDocument, ChatMessage
|
||||
from modules.datamodels.datamodelChat import ExtractedContent
|
||||
from modules.datamodels.datamodelChat import ChatContentExtracted
|
||||
from modules.services.serviceExtraction.mainServiceExtraction import ExtractionService
|
||||
from modules.services.serviceGeneration.subDocumentUtility import getFileExtension, getMimeTypeFromExtension, detectContentTypeFromData
|
||||
from modules.shared.timezoneUtils import get_utc_timestamp
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from typing import Dict, Any, List, Optional
|
|||
from datetime import datetime, UTC
|
||||
|
||||
from modules.workflows.methods.methodBase import MethodBase, action
|
||||
from modules.datamodels.datamodelWorkflow import ActionResult
|
||||
from modules.datamodels.datamodelChat import ActionResult
|
||||
from modules.datamodels.datamodelAi import AiCallOptions, OperationType, Priority
|
||||
from modules.datamodels.datamodelChat import ChatDocument
|
||||
from modules.datamodels.datamodelWeb import WebResearchRequest, WebResearchOptions
|
||||
|
|
@ -204,7 +204,7 @@ For large datasets, set "continue": true to indicate more data is coming, and we
|
|||
# Parse JSON response from AI with streaming support
|
||||
import json
|
||||
import re
|
||||
from modules.datamodels.datamodelWorkflow import ActionDocument
|
||||
from modules.datamodels.datamodelChat import ActionDocument
|
||||
|
||||
action_documents = []
|
||||
all_data_chunks = [] # Store all data chunks for merging
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from typing import Dict, Any, List, Optional
|
|||
from datetime import datetime, UTC
|
||||
|
||||
from modules.workflows.methods.methodBase import MethodBase, action
|
||||
from modules.datamodels.datamodelWorkflow import ActionResult, ActionDocument
|
||||
from modules.datamodels.datamodelChat import ActionResult, ActionDocument
|
||||
from modules.datamodels.datamodelChat import ChatDocument
|
||||
from modules.datamodels.datamodelAi import AiCallOptions, OperationType, Priority
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ class MethodDocument(MethodBase):
|
|||
action_documents = []
|
||||
|
||||
for i, chatDocument in enumerate(chatDocuments):
|
||||
# Extract text content from this document using new ExtractedContent structure
|
||||
# Extract text content from this document using new extracted content structure
|
||||
text_content = ""
|
||||
try:
|
||||
ec = all_extracted_content[i] if i < len(all_extracted_content) else None
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import uuid
|
|||
import requests
|
||||
|
||||
from modules.workflows.methods.methodBase import MethodBase, action
|
||||
from modules.datamodels.datamodelWorkflow import ActionResult, ActionDocument
|
||||
from modules.datamodels.datamodelChat import ActionResult, ActionDocument
|
||||
from modules.datamodels.datamodelAi import AiCallOptions, OperationType, Priority, AiCallRequest
|
||||
from modules.datamodels.datamodelChat import ChatDocument
|
||||
from modules.datamodels.datamodelUam import ConnectionStatus
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import aiohttp
|
|||
import asyncio
|
||||
|
||||
from modules.workflows.methods.methodBase import MethodBase, action
|
||||
from modules.datamodels.datamodelWorkflow import ActionResult, ActionDocument
|
||||
from modules.datamodels.datamodelChat import ActionResult, ActionDocument
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import logging
|
||||
from typing import Dict, Any, List
|
||||
from modules.datamodels.datamodelWorkflow import ActionResult, TaskAction, TaskStep
|
||||
from modules.datamodels.datamodelChat import ActionResult, ActionItem, TaskStep
|
||||
from modules.datamodels.datamodelChat import ChatWorkflow
|
||||
from modules.workflows.processing.shared.methodDiscovery import methods
|
||||
|
||||
|
|
@ -65,7 +65,7 @@ class ActionExecutor:
|
|||
logger.error(f"Error executing compound action {compoundActionName}: {str(e)}")
|
||||
raise
|
||||
|
||||
async def executeSingleAction(self, action: TaskAction, workflow: ChatWorkflow, taskStep: TaskStep,
|
||||
async def executeSingleAction(self, action: ActionItem, workflow: ChatWorkflow, taskStep: TaskStep,
|
||||
taskIndex: int = None, actionIndex: int = None, totalActions: int = None) -> ActionResult:
|
||||
"""Execute a single action and return ActionResult with enhanced document processing"""
|
||||
try:
|
||||
|
|
@ -199,7 +199,7 @@ class ActionExecutor:
|
|||
# Join all document results with separators
|
||||
return "\n\n---\n\n".join(resultParts) if resultParts else ""
|
||||
|
||||
async def _createActionCompletionMessage(self, action: TaskAction, result: ActionResult, workflow: ChatWorkflow,
|
||||
async def _createActionCompletionMessage(self, action: ActionItem, result: ActionResult, workflow: ChatWorkflow,
|
||||
taskStep: TaskStep, taskIndex: int, actionIndex: int, totalActions: int):
|
||||
"""Create action completion message with documents (generic)"""
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import logging
|
||||
from typing import Dict, Any, Optional, List
|
||||
from modules.datamodels.datamodelWorkflow import TaskPlan, TaskStep, ActionResult, ReviewResult
|
||||
from modules.datamodels.datamodelChat import TaskPlan, TaskStep, ActionResult, ReviewResult
|
||||
from modules.datamodels.datamodelChat import ChatWorkflow
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
import json
|
||||
import logging
|
||||
from typing import Dict, Any
|
||||
from modules.datamodels.datamodelWorkflow import TaskStep, TaskContext, TaskPlan
|
||||
from modules.datamodels.datamodelChat import TaskStep, TaskContext, TaskPlan
|
||||
from modules.datamodels.datamodelAi import AiCallOptions, OperationType, ProcessingMode, Priority
|
||||
from modules.workflows.processing.shared.promptGenerationTaskplan import (
|
||||
createTaskPlanningPromptTemplate
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import json
|
|||
import logging
|
||||
import uuid
|
||||
from typing import List, Dict, Any
|
||||
from modules.datamodels.datamodelWorkflow import (
|
||||
TaskStep, TaskContext, TaskResult, TaskAction, TaskStatus,
|
||||
from modules.datamodels.datamodelChat import (
|
||||
TaskStep, TaskContext, TaskResult, ActionItem, TaskStatus,
|
||||
ActionResult, ReviewResult, ReviewContext
|
||||
)
|
||||
from modules.datamodels.datamodelChat import ChatWorkflow
|
||||
|
|
@ -26,8 +26,8 @@ class ActionplanMode(BaseMode):
|
|||
def __init__(self, services, workflow):
|
||||
super().__init__(services, workflow)
|
||||
|
||||
async def generateTaskActions(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
||||
previousResults: List = None, enhancedContext: TaskContext = None) -> List[TaskAction]:
|
||||
async def generateActionItems(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
||||
previousResults: List = None, enhancedContext: TaskContext = None) -> List[ActionItem]:
|
||||
"""Generate actions for a given task step using batch planning approach"""
|
||||
try:
|
||||
# Check workflow status before generating actions
|
||||
|
|
@ -176,7 +176,7 @@ class ActionplanMode(BaseMode):
|
|||
logger.error("Generated actions failed validation")
|
||||
raise Exception("AI-generated actions failed validation - AI is required for action generation")
|
||||
|
||||
# Convert to TaskAction objects
|
||||
# Convert to ActionItem objects
|
||||
taskActions = []
|
||||
for i, a in enumerate(actions):
|
||||
if not isinstance(a, dict):
|
||||
|
|
@ -193,7 +193,7 @@ class ActionplanMode(BaseMode):
|
|||
# Old separate format: method + action fields
|
||||
method_name = a.get('method', 'unknown')
|
||||
|
||||
taskAction = self._createTaskAction({
|
||||
taskAction = self._createActionItem({
|
||||
"execMethod": method_name,
|
||||
"execAction": action_name,
|
||||
"execParameters": a.get('parameters', {}),
|
||||
|
|
@ -207,7 +207,7 @@ class ActionplanMode(BaseMode):
|
|||
if taskAction:
|
||||
taskActions.append(taskAction)
|
||||
else:
|
||||
logger.warning(f"Skipping invalid action {i+1}: failed to create TaskAction")
|
||||
logger.warning(f"Skipping invalid action {i+1}: failed to create ActionItem")
|
||||
|
||||
validActions = [ta for ta in taskActions if ta]
|
||||
|
||||
|
|
@ -216,7 +216,7 @@ class ActionplanMode(BaseMode):
|
|||
|
||||
return validActions
|
||||
except Exception as e:
|
||||
logger.error(f"Error in generateTaskActions: {str(e)}")
|
||||
logger.error(f"Error in generateActionItems: {str(e)}")
|
||||
return []
|
||||
|
||||
|
||||
|
|
@ -250,7 +250,7 @@ class ActionplanMode(BaseMode):
|
|||
if retryContext:
|
||||
retryContext.retry_count = attempt + 1
|
||||
|
||||
actions = await self.generateTaskActions(taskStep, workflow,
|
||||
actions = await self.generateActionItems(taskStep, workflow,
|
||||
previousResults=retryContext.previous_results,
|
||||
enhancedContext=retryContext)
|
||||
|
||||
|
|
@ -415,7 +415,7 @@ class ActionplanMode(BaseMode):
|
|||
error="Task failed after all retries."
|
||||
)
|
||||
|
||||
async def _reviewTaskCompletion(self, taskStep: TaskStep, taskActions: List[TaskAction],
|
||||
async def _reviewTaskCompletion(self, taskStep: TaskStep, taskActions: List[ActionItem],
|
||||
actionResults: List[ActionResult], workflow: ChatWorkflow) -> ReviewResult:
|
||||
"""Review task completion and determine success/failure/retry"""
|
||||
try:
|
||||
|
|
@ -562,7 +562,7 @@ class ActionplanMode(BaseMode):
|
|||
quality_score=0
|
||||
)
|
||||
|
||||
def _createTaskAction(self, actionData: Dict[str, Any]) -> TaskAction:
|
||||
def _createActionItem(self, actionData: Dict[str, Any]) -> ActionItem:
|
||||
"""Creates a new task action"""
|
||||
try:
|
||||
# Ensure ID is present
|
||||
|
|
@ -584,14 +584,14 @@ class ActionplanMode(BaseMode):
|
|||
if "execParameters" not in actionData:
|
||||
actionData["execParameters"] = {}
|
||||
|
||||
# Use generic field separation based on TaskAction model
|
||||
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(TaskAction, actionData)
|
||||
# Use generic field separation based on ActionItem model
|
||||
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(ActionItem, actionData)
|
||||
|
||||
# Create action in database
|
||||
createdAction = self.services.interfaceDbChat.db.recordCreate(TaskAction, simpleFields)
|
||||
createdAction = self.services.interfaceDbChat.db.recordCreate(ActionItem, simpleFields)
|
||||
|
||||
# Convert to TaskAction model
|
||||
return TaskAction(
|
||||
# Convert to ActionItem model
|
||||
return ActionItem(
|
||||
id=createdAction["id"],
|
||||
execMethod=createdAction["execMethod"],
|
||||
execAction=createdAction["execAction"],
|
||||
|
|
@ -704,7 +704,7 @@ class ActionplanMode(BaseMode):
|
|||
except Exception as e:
|
||||
logger.error(f"Error setting workflow totals: {str(e)}")
|
||||
|
||||
def _createTaskAction(self, actionData: Dict[str, Any]) -> TaskAction:
|
||||
def _createActionItem(self, actionData: Dict[str, Any]) -> ActionItem:
|
||||
"""Creates a new task action"""
|
||||
try:
|
||||
import uuid
|
||||
|
|
@ -728,14 +728,14 @@ class ActionplanMode(BaseMode):
|
|||
if "execParameters" not in actionData:
|
||||
actionData["execParameters"] = {}
|
||||
|
||||
# Use generic field separation based on TaskAction model
|
||||
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(TaskAction, actionData)
|
||||
# Use generic field separation based on ActionItem model
|
||||
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(ActionItem, actionData)
|
||||
|
||||
# Create action in database
|
||||
createdAction = self.services.interfaceDbChat.db.recordCreate(TaskAction, simpleFields)
|
||||
createdAction = self.services.interfaceDbChat.db.recordCreate(ActionItem, simpleFields)
|
||||
|
||||
# Convert to TaskAction model
|
||||
return TaskAction(
|
||||
# Convert to ActionItem model
|
||||
return ActionItem(
|
||||
id=createdAction["id"],
|
||||
execMethod=createdAction["execMethod"],
|
||||
execAction=createdAction["execAction"],
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
from abc import ABC, abstractmethod
|
||||
import logging
|
||||
from typing import List, Dict, Any
|
||||
from modules.datamodels.datamodelWorkflow import TaskStep, TaskContext, TaskResult, TaskAction
|
||||
from modules.datamodels.datamodelChat import TaskStep, TaskContext, TaskResult, ActionItem
|
||||
from modules.datamodels.datamodelChat import ChatWorkflow
|
||||
from modules.workflows.processing.core.taskPlanner import TaskPlanner
|
||||
from modules.workflows.processing.core.actionExecutor import ActionExecutor
|
||||
|
|
@ -46,8 +46,8 @@ class BaseMode(ABC):
|
|||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def generateTaskActions(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
||||
previousResults: List = None, enhancedContext: TaskContext = None) -> List[TaskAction]:
|
||||
async def generateActionItems(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
||||
previousResults: List = None, enhancedContext: TaskContext = None) -> List[ActionItem]:
|
||||
"""Generate actions for a task step - must be implemented by concrete modes"""
|
||||
pass
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import re
|
|||
import time
|
||||
from datetime import datetime, timezone
|
||||
from typing import List, Dict, Any
|
||||
from modules.datamodels.datamodelWorkflow import (
|
||||
TaskStep, TaskContext, TaskResult, TaskAction, TaskStatus,
|
||||
from modules.datamodels.datamodelChat import (
|
||||
TaskStep, TaskContext, TaskResult, ActionItem, TaskStatus,
|
||||
ActionResult
|
||||
)
|
||||
from modules.datamodels.datamodelChat import ChatWorkflow
|
||||
|
|
@ -38,8 +38,8 @@ class ReactMode(BaseMode):
|
|||
self.currentIntent = None
|
||||
# Placeholder service no longer used; prompts are generated directly
|
||||
|
||||
async def generateTaskActions(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
||||
previousResults: List = None, enhancedContext: TaskContext = None) -> List[TaskAction]:
|
||||
async def generateActionItems(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
||||
previousResults: List = None, enhancedContext: TaskContext = None) -> List[ActionItem]:
|
||||
"""React mode doesn't use batch action generation - actions are generated iteratively"""
|
||||
# React mode generates actions one at a time in the execution loop
|
||||
return []
|
||||
|
|
@ -264,12 +264,12 @@ class ReactMode(BaseMode):
|
|||
if 'language' not in parameters and hasattr(self.services, 'user') and getattr(self.services.user, 'language', None):
|
||||
parameters['language'] = self.services.user.language
|
||||
|
||||
# Build a synthetic TaskAction for execution routing and labels
|
||||
# Build a synthetic ActionItem for execution routing and labels
|
||||
currentRound = getattr(self.workflow, 'currentRound', 0)
|
||||
currentTask = getattr(self.workflow, 'currentTask', 0)
|
||||
resultLabel = f"round{currentRound}_task{currentTask}_action{stepIndex}_results"
|
||||
|
||||
taskAction = self._createTaskAction({
|
||||
taskAction = self._createActionItem({
|
||||
"execMethod": methodName,
|
||||
"execAction": actionName,
|
||||
"execParameters": parameters,
|
||||
|
|
@ -463,7 +463,7 @@ class ReactMode(BaseMode):
|
|||
async def _refineDecide(self, context: TaskContext, observation: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Refine: decide continue or stop, with reason"""
|
||||
# Create proper ReviewContext for extractReviewContent
|
||||
from modules.datamodels.datamodelWorkflow import ReviewContext
|
||||
from modules.datamodels.datamodelChat import ReviewContext
|
||||
reviewContext = ReviewContext(
|
||||
task_step=context.task_step,
|
||||
task_actions=[],
|
||||
|
|
@ -662,7 +662,7 @@ Return only the user-friendly message, no technical details."""
|
|||
logger.error(f"Error generating action result message: {str(e)}")
|
||||
return f"{method}.{actionName} action completed"
|
||||
|
||||
def _createTaskAction(self, actionData: Dict[str, Any]) -> TaskAction:
|
||||
def _createActionItem(self, actionData: Dict[str, Any]) -> ActionItem:
|
||||
"""Creates a new task action for React mode"""
|
||||
try:
|
||||
import uuid
|
||||
|
|
@ -686,14 +686,14 @@ Return only the user-friendly message, no technical details."""
|
|||
if "execParameters" not in actionData:
|
||||
actionData["execParameters"] = {}
|
||||
|
||||
# Use generic field separation based on TaskAction model
|
||||
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(TaskAction, actionData)
|
||||
# Use generic field separation based on ActionItem model
|
||||
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(ActionItem, actionData)
|
||||
|
||||
# Create action in database
|
||||
createdAction = self.services.interfaceDbChat.db.recordCreate(TaskAction, simpleFields)
|
||||
createdAction = self.services.interfaceDbChat.db.recordCreate(ActionItem, simpleFields)
|
||||
|
||||
# Convert to TaskAction model
|
||||
return TaskAction(
|
||||
# Convert to ActionItem model
|
||||
return ActionItem(
|
||||
id=createdAction["id"],
|
||||
execMethod=createdAction["execMethod"],
|
||||
execAction=createdAction["execAction"],
|
||||
|
|
@ -753,7 +753,7 @@ Return only the user-friendly message, no technical details."""
|
|||
except Exception as e:
|
||||
logger.error(f"Error updating workflow before executing action: {str(e)}")
|
||||
|
||||
def _createTaskAction(self, actionData: Dict[str, Any]) -> TaskAction:
|
||||
def _createActionItem(self, actionData: Dict[str, Any]) -> ActionItem:
|
||||
"""Creates a new task action for React mode"""
|
||||
try:
|
||||
import uuid
|
||||
|
|
@ -777,14 +777,14 @@ Return only the user-friendly message, no technical details."""
|
|||
if "execParameters" not in actionData:
|
||||
actionData["execParameters"] = {}
|
||||
|
||||
# Use generic field separation based on TaskAction model
|
||||
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(TaskAction, actionData)
|
||||
# Use generic field separation based on ActionItem model
|
||||
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(ActionItem, actionData)
|
||||
|
||||
# Create action in database
|
||||
createdAction = self.services.interfaceDbChat.db.recordCreate(TaskAction, simpleFields)
|
||||
createdAction = self.services.interfaceDbChat.db.recordCreate(ActionItem, simpleFields)
|
||||
|
||||
# Convert to TaskAction model
|
||||
return TaskAction(
|
||||
# Convert to ActionItem model
|
||||
return ActionItem(
|
||||
id=createdAction["id"],
|
||||
execMethod=createdAction["execMethod"],
|
||||
execAction=createdAction["execAction"],
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
import logging
|
||||
from typing import List
|
||||
from datetime import datetime, UTC
|
||||
from modules.datamodels.datamodelWorkflow import TaskStep
|
||||
from modules.datamodels.datamodelWorkflow import ActionResult
|
||||
from modules.datamodels.datamodelChat import TaskStep
|
||||
from modules.datamodels.datamodelChat import ActionResult
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import importlib
|
|||
import pkgutil
|
||||
import inspect
|
||||
from typing import Any, Dict, List
|
||||
from modules.datamodels.datamodelWorkflow import TaskContext, ReviewContext, DocumentExchange
|
||||
from modules.datamodels.datamodelChat import TaskContext, ReviewContext, DocumentExchange
|
||||
from modules.workflows.methods.methodBase import MethodBase
|
||||
|
||||
# Set up logger
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Handles prompt templates and extraction functions for actionplan mode action han
|
|||
import json
|
||||
import logging
|
||||
from typing import Dict, Any, List
|
||||
from modules.datamodels.datamodelWorkflow import PromptBundle, PromptPlaceholder
|
||||
from modules.datamodels.datamodelChat import PromptBundle, PromptPlaceholder
|
||||
from modules.workflows.processing.shared.placeholderFactory import (
|
||||
extractUserPrompt,
|
||||
extractAvailableDocumentsSummary,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ Handles prompt templates for react mode action handling.
|
|||
"""
|
||||
|
||||
from typing import Any, List
|
||||
from modules.datamodels.datamodelWorkflow import PromptBundle, PromptPlaceholder
|
||||
from modules.datamodels.datamodelChat import PromptBundle, PromptPlaceholder
|
||||
from modules.workflows.processing.shared.placeholderFactory import (
|
||||
extractUserPrompt,
|
||||
extractUserLanguage,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Handles prompt templates and extraction functions for task planning phase.
|
|||
import json
|
||||
import logging
|
||||
from typing import Dict, Any, List
|
||||
from modules.datamodels.datamodelWorkflow import PromptBundle, PromptPlaceholder
|
||||
from modules.datamodels.datamodelChat import PromptBundle, PromptPlaceholder
|
||||
from modules.workflows.processing.shared.placeholderFactory import (
|
||||
extractUserPrompt,
|
||||
extractAvailableDocumentsSummary,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import logging
|
||||
from typing import Dict, Any, Optional, List
|
||||
from modules.datamodels.datamodelWorkflow import TaskStep, TaskContext, TaskPlan, TaskResult, ReviewResult
|
||||
from modules.datamodels.datamodelChat import TaskStep, TaskContext, TaskPlan, TaskResult, ReviewResult
|
||||
from modules.datamodels.datamodelChat import ChatWorkflow
|
||||
from modules.workflows.processing.modes.modeBase import BaseMode
|
||||
from modules.workflows.processing.modes.modeActionplan import ActionplanMode
|
||||
|
|
@ -84,7 +84,7 @@ class WorkflowProcessor:
|
|||
logger.error(f"Error in executeTask: {str(e)}")
|
||||
raise
|
||||
|
||||
async def generateTaskActions(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
||||
async def generateActionItems(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
||||
previousResults: List = None, enhancedContext: TaskContext = None) -> List:
|
||||
"""Generate actions for a task step using the appropriate mode"""
|
||||
try:
|
||||
|
|
@ -96,9 +96,9 @@ class WorkflowProcessor:
|
|||
logger.info(f"Mode: {workflow.workflowMode}")
|
||||
|
||||
# Delegate to the appropriate mode
|
||||
return await self.mode.generateTaskActions(taskStep, workflow, previousResults, enhancedContext)
|
||||
return await self.mode.generateActionItems(taskStep, workflow, previousResults, enhancedContext)
|
||||
except Exception as e:
|
||||
logger.error(f"Error in generateTaskActions: {str(e)}")
|
||||
logger.error(f"Error in generateActionItems: {str(e)}")
|
||||
raise
|
||||
|
||||
def updateWorkflowAfterTaskPlanCreated(self, totalTasks: int):
|
||||
|
|
|
|||
|
|
@ -8,10 +8,9 @@ from modules.datamodels.datamodelChat import (
|
|||
UserInputRequest,
|
||||
ChatMessage,
|
||||
ChatWorkflow,
|
||||
ChatDocument,
|
||||
WorkflowResult
|
||||
ChatDocument
|
||||
)
|
||||
from modules.datamodels.datamodelWorkflow import TaskItem, TaskStatus, TaskContext
|
||||
from modules.datamodels.datamodelChat import TaskItem, TaskStatus, TaskContext
|
||||
from modules.workflows.processing.workflowProcessor import WorkflowProcessor, WorkflowStoppedException
|
||||
from modules.shared.timezoneUtils import get_utc_timestamp
|
||||
|
||||
|
|
@ -160,8 +159,8 @@ class WorkflowManager:
|
|||
self.workflowProcessor = WorkflowProcessor(self.services, workflow)
|
||||
message = await self._sendFirstMessage(userInput, workflow)
|
||||
task_plan = await self._planTasks(userInput, workflow)
|
||||
workflow_result = await self._executeTasks(task_plan, workflow)
|
||||
await self._processWorkflowResults(workflow, workflow_result, message)
|
||||
await self._executeTasks(task_plan, workflow)
|
||||
await self._processWorkflowResults(workflow, message)
|
||||
|
||||
except WorkflowStoppedException:
|
||||
self._handleWorkflowStop(workflow)
|
||||
|
|
@ -359,8 +358,8 @@ class WorkflowManager:
|
|||
logger.info(f"Executing workflow mode={workflow_mode} with {len(task_plan.tasks)} tasks")
|
||||
return task_plan
|
||||
|
||||
async def _executeTasks(self, task_plan, workflow: ChatWorkflow) -> WorkflowResult:
|
||||
"""Execute all tasks in the task plan"""
|
||||
async def _executeTasks(self, task_plan, workflow: ChatWorkflow) -> None:
|
||||
"""Execute all tasks in the task plan and update workflow status."""
|
||||
handling = self.workflowProcessor
|
||||
total_tasks = len(task_plan.tasks)
|
||||
all_task_results: List = []
|
||||
|
|
@ -404,16 +403,12 @@ class WorkflowManager:
|
|||
if task_result.success and task_result.feedback:
|
||||
previous_results.append(task_result.feedback)
|
||||
|
||||
return WorkflowResult(
|
||||
status="completed",
|
||||
completed_tasks=len(all_task_results),
|
||||
total_tasks=total_tasks,
|
||||
execution_time=0.0,
|
||||
final_results_count=len(all_task_results)
|
||||
)
|
||||
# Mark workflow as completed; error/stop cases update status elsewhere
|
||||
workflow.status = "completed"
|
||||
return None
|
||||
|
||||
async def _processWorkflowResults(self, workflow: ChatWorkflow, workflow_result: WorkflowResult, initial_message: ChatMessage) -> None:
|
||||
"""Process workflow results and create appropriate messages"""
|
||||
async def _processWorkflowResults(self, workflow: ChatWorkflow, initial_message: ChatMessage) -> None:
|
||||
"""Process workflow results based on workflow status and create appropriate messages"""
|
||||
try:
|
||||
try:
|
||||
self.workflowProcessor._checkWorkflowStopped(workflow)
|
||||
|
|
@ -451,7 +446,7 @@ class WorkflowManager:
|
|||
})
|
||||
return
|
||||
|
||||
if workflow_result.status == 'stopped':
|
||||
if workflow.status == 'stopped':
|
||||
# Create stopped message
|
||||
stopped_message = {
|
||||
"workflowId": workflow.id,
|
||||
|
|
@ -493,12 +488,12 @@ class WorkflowManager:
|
|||
"progress": 100
|
||||
})
|
||||
return
|
||||
elif workflow_result.status == 'failed':
|
||||
elif workflow.status == 'failed':
|
||||
# Create error message
|
||||
error_message = {
|
||||
"workflowId": workflow.id,
|
||||
"role": "assistant",
|
||||
"message": f"Workflow failed: {workflow_result.error or 'Unknown error'}",
|
||||
"message": f"Workflow failed: {'Unknown error'}",
|
||||
"status": "last",
|
||||
"sequenceNr": len(workflow.messages) + 1,
|
||||
"publishedAt": self.services.utils.getUtcTimestamp(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue