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 datamodelUam as uam
|
||||||
from . import datamodelSecurity as security
|
from . import datamodelSecurity as security
|
||||||
from . import datamodelNeutralizer as neutralizer
|
from . import datamodelNeutralizer as neutralizer
|
||||||
from . import datamodelWorkflow as workflow
|
|
||||||
from . import datamodelChat as chat
|
from . import datamodelChat as chat
|
||||||
from . import datamodelFiles as files
|
from . import datamodelFiles as files
|
||||||
from . import datamodelVoice as voice
|
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
|
from modules.shared.timezoneUtils import get_utc_timestamp
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
class ChatStat(BaseModel, ModelMixin):
|
class ChatStat(BaseModel, ModelMixin):
|
||||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key")
|
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)")
|
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")
|
bytesReceived: Optional[int] = Field(None, description="Number of bytes received")
|
||||||
successRate: Optional[float] = Field(None, description="Success rate of operations")
|
successRate: Optional[float] = Field(None, description="Success rate of operations")
|
||||||
errorCount: Optional[int] = Field(None, description="Number of errors encountered")
|
errorCount: Optional[int] = Field(None, description="Number of errors encountered")
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"ChatStat",
|
"ChatStat",
|
||||||
{"en": "Chat Statistics", "fr": "Statistiques de chat"},
|
{"en": "Chat Statistics", "fr": "Statistiques de chat"},
|
||||||
|
|
@ -35,7 +32,6 @@ register_model_labels(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ChatLog(BaseModel, ModelMixin):
|
class ChatLog(BaseModel, ModelMixin):
|
||||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key")
|
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key")
|
||||||
workflowId: str = Field(description="Foreign key to workflow")
|
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")
|
status: Optional[str] = Field(None, description="Status of the log entry")
|
||||||
progress: Optional[float] = Field(None, description="Progress indicator (0.0 to 1.0)")
|
progress: Optional[float] = Field(None, description="Progress indicator (0.0 to 1.0)")
|
||||||
performance: Optional[Dict[str, Any]] = Field(None, description="Performance metrics")
|
performance: Optional[Dict[str, Any]] = Field(None, description="Performance metrics")
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"ChatLog",
|
"ChatLog",
|
||||||
{"en": "Chat Log", "fr": "Journal de chat"},
|
{"en": "Chat Log", "fr": "Journal de chat"},
|
||||||
|
|
@ -62,7 +56,6 @@ register_model_labels(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ChatDocument(BaseModel, ModelMixin):
|
class ChatDocument(BaseModel, ModelMixin):
|
||||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key")
|
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key")
|
||||||
messageId: str = Field(description="Foreign key to message")
|
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")
|
taskNumber: Optional[int] = Field(None, description="Task number within round")
|
||||||
actionNumber: Optional[int] = Field(None, description="Action number within task")
|
actionNumber: Optional[int] = Field(None, description="Action number within task")
|
||||||
actionId: Optional[str] = Field(None, description="ID of the action that created this document")
|
actionId: Optional[str] = Field(None, description="ID of the action that created this document")
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"ChatDocument",
|
"ChatDocument",
|
||||||
{"en": "Chat Document", "fr": "Document de chat"},
|
{"en": "Chat Document", "fr": "Document de chat"},
|
||||||
|
|
@ -93,7 +84,6 @@ register_model_labels(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ContentMetadata(BaseModel, ModelMixin):
|
class ContentMetadata(BaseModel, ModelMixin):
|
||||||
size: int = Field(description="Content size in bytes")
|
size: int = Field(description="Content size in bytes")
|
||||||
pages: Optional[int] = Field(None, description="Number of pages for multi-page content")
|
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")
|
durationSec: Optional[float] = Field(None, description="Duration in seconds for media")
|
||||||
mimeType: str = Field(description="MIME type of the content")
|
mimeType: str = Field(description="MIME type of the content")
|
||||||
base64Encoded: bool = Field(description="Whether the data is base64 encoded")
|
base64Encoded: bool = Field(description="Whether the data is base64 encoded")
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"ContentMetadata",
|
"ContentMetadata",
|
||||||
{"en": "Content Metadata", "fr": "Métadonnées du contenu"},
|
{"en": "Content Metadata", "fr": "Métadonnées du contenu"},
|
||||||
|
|
@ -124,13 +112,10 @@ register_model_labels(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ContentItem(BaseModel, ModelMixin):
|
class ContentItem(BaseModel, ModelMixin):
|
||||||
label: str = Field(description="Content label")
|
label: str = Field(description="Content label")
|
||||||
data: str = Field(description="Extracted text content")
|
data: str = Field(description="Extracted text content")
|
||||||
metadata: ContentMetadata = Field(description="Content metadata")
|
metadata: ContentMetadata = Field(description="Content metadata")
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"ContentItem",
|
"ContentItem",
|
||||||
{"en": "Content Item", "fr": "Élément de contenu"},
|
{"en": "Content Item", "fr": "Élément de contenu"},
|
||||||
|
|
@ -141,14 +126,11 @@ register_model_labels(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class ChatContentExtracted(BaseModel, ModelMixin):
|
||||||
class ExtractedContent(BaseModel, ModelMixin):
|
|
||||||
id: str = Field(description="Reference to source ChatDocument")
|
id: str = Field(description="Reference to source ChatDocument")
|
||||||
contents: List[ContentItem] = Field(default_factory=list, description="List of content items")
|
contents: List[ContentItem] = Field(default_factory=list, description="List of content items")
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"ExtractedContent",
|
"ChatContentExtracted",
|
||||||
{"en": "Extracted Content", "fr": "Contenu extrait"},
|
{"en": "Extracted Content", "fr": "Contenu extrait"},
|
||||||
{
|
{
|
||||||
"id": {"en": "Object ID", "fr": "ID de l'objet"},
|
"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")
|
actionNumber: Optional[int] = Field(None, description="Action number within task")
|
||||||
taskProgress: Optional[str] = Field(None, description="Task progress status: pending, running, success, fail, retry")
|
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")
|
actionProgress: Optional[str] = Field(None, description="Action progress status: pending, running, success, fail")
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"ChatMessage",
|
"ChatMessage",
|
||||||
{"en": "Chat Message", "fr": "Message de chat"},
|
{"en": "Chat Message", "fr": "Message de chat"},
|
||||||
|
|
@ -206,7 +186,6 @@ register_model_labels(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ChatWorkflow(BaseModel, ModelMixin):
|
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)
|
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)
|
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"}},
|
{"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)
|
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(
|
register_model_labels(
|
||||||
"ChatWorkflow",
|
"ChatWorkflow",
|
||||||
{"en": "Chat Workflow", "fr": "Flux de travail de chat"},
|
{"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):
|
class UserInputRequest(BaseModel, ModelMixin):
|
||||||
prompt: str = Field(description="Prompt for the user")
|
prompt: str = Field(description="Prompt for the user")
|
||||||
listFileId: List[str] = Field(default_factory=list, description="List of file IDs")
|
listFileId: List[str] = Field(default_factory=list, description="List of file IDs")
|
||||||
userLanguage: str = Field(default="en", description="User's preferred language")
|
userLanguage: str = Field(default="en", description="User's preferred language")
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"UserInputRequest",
|
"UserInputRequest", {"en": "User Input Request", "fr": "Demande de saisie utilisateur"},
|
||||||
{"en": "User Input Request", "fr": "Demande de saisie utilisateur"},
|
|
||||||
{
|
{
|
||||||
"prompt": {"en": "Prompt", "fr": "Invite"},
|
"prompt": {"en": "Prompt", "fr": "Invite"},
|
||||||
"listFileId": {"en": "File IDs", "fr": "IDs des fichiers"},
|
"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")
|
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")
|
id: str = Field(description="Extraction id or source document id")
|
||||||
parts: List[ContentPart] = Field(default_factory=list, description="List of extracted parts")
|
parts: List[ContentPart] = Field(default_factory=list, description="List of extracted parts")
|
||||||
summary: Optional[Dict[str, Any]] = Field(default=None, description="Optional extraction summary")
|
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]:
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
return super().to_dict()
|
return super().to_dict()
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"FileItem",
|
"FileItem",
|
||||||
{"en": "File Item", "fr": "Élément de fichier"},
|
{"en": "File Item", "fr": "Élément de fichier"},
|
||||||
|
|
@ -35,7 +33,6 @@ register_model_labels(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class FilePreview(BaseModel, ModelMixin):
|
class FilePreview(BaseModel, ModelMixin):
|
||||||
content: Union[str, bytes] = Field(description="File content (text or binary)")
|
content: Union[str, bytes] = Field(description="File content (text or binary)")
|
||||||
mimeType: str = Field(description="MIME type of the file")
|
mimeType: str = Field(description="MIME type of the file")
|
||||||
|
|
@ -49,8 +46,6 @@ class FilePreview(BaseModel, ModelMixin):
|
||||||
if isinstance(data.get("content"), bytes):
|
if isinstance(data.get("content"), bytes):
|
||||||
data["content"] = base64.b64encode(data["content"]).decode("utf-8")
|
data["content"] = base64.b64encode(data["content"]).decode("utf-8")
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"FilePreview",
|
"FilePreview",
|
||||||
{"en": "File Preview", "fr": "Aperçu du fichier"},
|
{"en": "File Preview", "fr": "Aperçu du fichier"},
|
||||||
|
|
@ -64,13 +59,10 @@ register_model_labels(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class FileData(BaseModel, ModelMixin):
|
class FileData(BaseModel, ModelMixin):
|
||||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key")
|
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key")
|
||||||
data: str = Field(description="File data content")
|
data: str = Field(description="File data content")
|
||||||
base64Encoded: bool = Field(description="Whether the data is base64 encoded")
|
base64Encoded: bool = Field(description="Whether the data is base64 encoded")
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"FileData",
|
"FileData",
|
||||||
{"en": "File Data", "fr": "Données de fichier"},
|
{"en": "File Data", "fr": "Données de fichier"},
|
||||||
|
|
@ -80,5 +72,3 @@ register_model_labels(
|
||||||
"base64Encoded": {"en": "Base64 Encoded", "fr": "Encodé en Base64"},
|
"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)
|
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)
|
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)
|
sharepointTargetPath: str = Field(default="", description="SharePoint path to store neutralized files", frontend_type="text", frontend_readonly=False, frontend_required=False)
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"DataNeutraliserConfig",
|
"DataNeutraliserConfig",
|
||||||
{"en": "Data Neutralization Config", "fr": "Configuration de neutralisation des données"},
|
{"en": "Data Neutralization Config", "fr": "Configuration de neutralisation des données"},
|
||||||
|
|
@ -30,7 +28,6 @@ register_model_labels(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class DataNeutralizerAttributes(BaseModel, ModelMixin):
|
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)
|
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)
|
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)
|
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)
|
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)
|
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(
|
register_model_labels(
|
||||||
"DataNeutralizerAttributes",
|
"DataNeutralizerAttributes",
|
||||||
{"en": "Neutralized Data Attribute", "fr": "Attribut de données neutralisées"},
|
{"en": "Neutralized Data Attribute", "fr": "Attribut de données neutralisées"},
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ class TokenStatus(str, Enum):
|
||||||
ACTIVE = "active"
|
ACTIVE = "active"
|
||||||
REVOKED = "revoked"
|
REVOKED = "revoked"
|
||||||
|
|
||||||
|
|
||||||
class Token(BaseModel, ModelMixin):
|
class Token(BaseModel, ModelMixin):
|
||||||
id: Optional[str] = None
|
id: Optional[str] = None
|
||||||
userId: str
|
userId: str
|
||||||
|
|
@ -33,8 +32,6 @@ class Token(BaseModel, ModelMixin):
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
use_enum_values = True
|
use_enum_values = True
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"Token",
|
"Token",
|
||||||
{"en": "Token", "fr": "Jeton"},
|
{"en": "Token", "fr": "Jeton"},
|
||||||
|
|
@ -57,7 +54,6 @@ register_model_labels(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class AuthEvent(BaseModel, ModelMixin):
|
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)
|
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)
|
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)
|
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)
|
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)
|
details: Optional[str] = Field(default=None, description="Additional details about the event", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"AuthEvent",
|
"AuthEvent",
|
||||||
{"en": "Authentication Event", "fr": "Événement d'authentification"},
|
{"en": "Authentication Event", "fr": "Événement d'authentification"},
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ class TicketFieldAttribute(BaseModel):
|
||||||
fieldName: str = Field(description="Human-readable field name")
|
fieldName: str = Field(description="Human-readable field name")
|
||||||
field: str = Field(description="Ticket field ID/key")
|
field: str = Field(description="Ticket field ID/key")
|
||||||
|
|
||||||
|
|
||||||
class TicketBase(ABC):
|
class TicketBase(ABC):
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def read_attributes(self) -> list[TicketFieldAttribute]: ...
|
async def read_attributes(self) -> list[TicketFieldAttribute]: ...
|
||||||
|
|
|
||||||
|
|
@ -13,20 +13,17 @@ class AuthAuthority(str, Enum):
|
||||||
GOOGLE = "google"
|
GOOGLE = "google"
|
||||||
MSFT = "msft"
|
MSFT = "msft"
|
||||||
|
|
||||||
|
|
||||||
class UserPrivilege(str, Enum):
|
class UserPrivilege(str, Enum):
|
||||||
SYSADMIN = "sysadmin"
|
SYSADMIN = "sysadmin"
|
||||||
ADMIN = "admin"
|
ADMIN = "admin"
|
||||||
USER = "user"
|
USER = "user"
|
||||||
|
|
||||||
|
|
||||||
class ConnectionStatus(str, Enum):
|
class ConnectionStatus(str, Enum):
|
||||||
ACTIVE = "active"
|
ACTIVE = "active"
|
||||||
EXPIRED = "expired"
|
EXPIRED = "expired"
|
||||||
REVOKED = "revoked"
|
REVOKED = "revoked"
|
||||||
PENDING = "pending"
|
PENDING = "pending"
|
||||||
|
|
||||||
|
|
||||||
class Mandate(BaseModel, ModelMixin):
|
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)
|
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)
|
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"}},
|
{"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)
|
enabled: bool = Field(default=True, description="Indicates whether the mandate is enabled", frontend_type="checkbox", frontend_readonly=False, frontend_required=False)
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"Mandate",
|
"Mandate",
|
||||||
{"en": "Mandate", "fr": "Mandat"},
|
{"en": "Mandate", "fr": "Mandat"},
|
||||||
|
|
@ -50,7 +45,6 @@ register_model_labels(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserConnection(BaseModel, ModelMixin):
|
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)
|
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)
|
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"}},
|
{"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)
|
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(
|
register_model_labels(
|
||||||
"UserConnection",
|
"UserConnection",
|
||||||
{"en": "User Connection", "fr": "Connexion utilisateur"},
|
{"en": "User Connection", "fr": "Connexion utilisateur"},
|
||||||
|
|
@ -98,7 +90,6 @@ register_model_labels(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class User(BaseModel, ModelMixin):
|
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)
|
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)
|
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"}},
|
{"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)
|
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(
|
register_model_labels(
|
||||||
"User",
|
"User",
|
||||||
{"en": "User", "fr": "Utilisateur"},
|
{"en": "User", "fr": "Utilisateur"},
|
||||||
|
|
@ -140,15 +129,10 @@ register_model_labels(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserInDB(User):
|
class UserInDB(User):
|
||||||
hashedPassword: Optional[str] = Field(None, description="Hash of the user password")
|
hashedPassword: Optional[str] = Field(None, description="Hash of the user password")
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"UserInDB",
|
"UserInDB",
|
||||||
{"en": "User Access", "fr": "Accès de l'utilisateur"},
|
{"en": "User Access", "fr": "Accès de l'utilisateur"},
|
||||||
{"hashedPassword": {"en": "Password hash", "fr": "Hachage de mot de passe"}},
|
{"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)
|
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)
|
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)
|
name: str = Field(description="Name of the prompt", frontend_type="text", frontend_readonly=False, frontend_required=True)
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"Prompt",
|
"Prompt",
|
||||||
{"en": "Prompt", "fr": "Invite"},
|
{"en": "Prompt", "fr": "Invite"},
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ class VoiceSettings(BaseModel, ModelMixin):
|
||||||
def to_dict(self) -> Dict[str, Any]:
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
return super().to_dict()
|
return super().to_dict()
|
||||||
|
|
||||||
|
|
||||||
register_model_labels(
|
register_model_labels(
|
||||||
"VoiceSettings",
|
"VoiceSettings",
|
||||||
{"en": "Voice Settings", "fr": "Paramètres vocaux"},
|
{"en": "Voice Settings", "fr": "Paramètres vocaux"},
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
"""Web-related modules"""
|
"""Web-related modules"""
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
|
||||||
from pydantic import BaseModel, Field, HttpUrl
|
from pydantic import BaseModel, Field, HttpUrl
|
||||||
from typing import List, Optional, Literal, Dict, Any
|
from typing import List, Optional, Literal, Dict, Any
|
||||||
from modules.shared.configuration import APP_CONFIG
|
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"))
|
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_answer: Optional[bool] = Field(default=None, description="Include AI answer")
|
||||||
include_raw_content: Optional[bool] = Field(default=None, description="Include raw content")
|
include_raw_content: Optional[bool] = Field(default=None, description="Include raw content")
|
||||||
|
|
||||||
|
|
||||||
class WebResearchRequest(BaseModel):
|
class WebResearchRequest(BaseModel):
|
||||||
"""Main web research request"""
|
"""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")
|
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")
|
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")
|
options: WebResearchOptions = Field(default_factory=WebResearchOptions, description="Advanced options")
|
||||||
|
|
||||||
|
|
||||||
class WebSearchResultItem(BaseModel):
|
class WebSearchResultItem(BaseModel):
|
||||||
"""Individual search result"""
|
"""Individual search result"""
|
||||||
title: str
|
title: str
|
||||||
url: HttpUrl
|
url: HttpUrl
|
||||||
raw_content: Optional[str] = Field(default=None, description="Raw HTML content")
|
raw_content: Optional[str] = Field(default=None, description="Raw HTML content")
|
||||||
|
|
||||||
|
|
||||||
class WebCrawlResultItem(BaseModel):
|
class WebCrawlResultItem(BaseModel):
|
||||||
"""Individual crawl result"""
|
"""Individual crawl result"""
|
||||||
url: HttpUrl
|
url: HttpUrl
|
||||||
content: str
|
content: str
|
||||||
|
|
||||||
|
|
||||||
class WebResearchDocumentData(BaseModel):
|
class WebResearchDocumentData(BaseModel):
|
||||||
"""Complete web research results"""
|
"""Complete web research results"""
|
||||||
user_prompt: str
|
user_prompt: str
|
||||||
|
|
@ -60,21 +54,14 @@ class WebResearchDocumentData(BaseModel):
|
||||||
individual_content: Optional[Dict[str, str]] = None # URL -> content mapping
|
individual_content: Optional[Dict[str, str]] = None # URL -> content mapping
|
||||||
debug_info: Optional[Dict[str, Any]] = None
|
debug_info: Optional[Dict[str, Any]] = None
|
||||||
|
|
||||||
|
|
||||||
class WebResearchActionDocument(ActionDocument):
|
class WebResearchActionDocument(ActionDocument):
|
||||||
documentData: WebResearchDocumentData
|
documentData: WebResearchDocumentData
|
||||||
|
|
||||||
|
|
||||||
class WebResearchActionResult(ActionResult):
|
class WebResearchActionResult(ActionResult):
|
||||||
documents: List[WebResearchActionDocument] = Field(default_factory=list)
|
documents: List[WebResearchActionDocument] = Field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
class WebResearchBase(ABC):
|
|
||||||
@abstractmethod
|
|
||||||
async def web_research(self, request: WebResearchRequest) -> WebResearchActionResult: ...
|
|
||||||
|
|
||||||
|
|
||||||
# Legacy models for connector compatibility
|
# Legacy models for connector compatibility
|
||||||
|
|
||||||
class WebSearchDocumentData(BaseModel):
|
class WebSearchDocumentData(BaseModel):
|
||||||
"""Search results document data"""
|
"""Search results document data"""
|
||||||
query: str
|
query: str
|
||||||
|
|
@ -153,5 +140,3 @@ class WebScrapeResultItem(BaseModel):
|
||||||
"""Individual scrape result"""
|
"""Individual scrape result"""
|
||||||
url: HttpUrl
|
url: HttpUrl
|
||||||
content: str
|
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,
|
WebSearchRequest,
|
||||||
WebCrawlRequest,
|
WebCrawlRequest,
|
||||||
)
|
)
|
||||||
from modules.datamodels.datamodelWorkflow import ActionDocument
|
from modules.datamodels.datamodelChat import ActionDocument
|
||||||
|
|
||||||
|
|
||||||
# Comprehensive model registry with capability tags and function mapping
|
# 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
|
import asyncio
|
||||||
|
|
||||||
from modules.interfaces.interfaceDbChatAccess import ChatAccess
|
from modules.interfaces.interfaceDbChatAccess import ChatAccess
|
||||||
from modules.datamodels.datamodelWorkflow import (
|
from modules.datamodels.datamodelChat import (
|
||||||
TaskAction,
|
ActionItem,
|
||||||
TaskResult,
|
TaskResult,
|
||||||
TaskItem,
|
TaskItem,
|
||||||
TaskStatus,
|
TaskStatus,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict, Any, List, Optional, Tuple, Union
|
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.datamodels.datamodelChat import ChatDocument
|
||||||
from modules.services.serviceExtraction.mainServiceExtraction import ExtractionService
|
from modules.services.serviceExtraction.mainServiceExtraction import ExtractionService
|
||||||
|
|
@ -909,7 +909,7 @@ class AiService:
|
||||||
|
|
||||||
logger.info(f"Extraction completed: {len(extracted_content)} documents")
|
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):
|
if isinstance(extracted_content, list):
|
||||||
context_parts = []
|
context_parts = []
|
||||||
chunk_count = 0
|
chunk_count = 0
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import logging
|
||||||
|
|
||||||
from .subRegistry import ExtractorRegistry, ChunkerRegistry
|
from .subRegistry import ExtractorRegistry, ChunkerRegistry
|
||||||
from .subPipeline import runExtraction, poolAndLimit, applyAiIfRequested
|
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
|
from modules.datamodels.datamodelChat import ChatDocument
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -17,7 +17,7 @@ class ExtractionService:
|
||||||
self._extractorRegistry = ExtractorRegistry()
|
self._extractorRegistry = ExtractorRegistry()
|
||||||
self._chunkerRegistry = ChunkerRegistry()
|
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.
|
Extract content from a list of ChatDocument objects.
|
||||||
|
|
||||||
|
|
@ -26,9 +26,9 @@ class ExtractionService:
|
||||||
options: Extraction options including maxSize, chunkAllowed, mergeStrategy, etc.
|
options: Extraction options including maxSize, chunkAllowed, mergeStrategy, etc.
|
||||||
|
|
||||||
Returns:
|
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
|
# Lazy import to avoid circular deps and heavy init at module import
|
||||||
from modules.interfaces.interfaceDbComponentObjects import getInterface
|
from modules.interfaces.interfaceDbComponentObjects import getInterface
|
||||||
|
|
@ -90,20 +90,20 @@ class ExtractionService:
|
||||||
|
|
||||||
def mergeAiResults(
|
def mergeAiResults(
|
||||||
self,
|
self,
|
||||||
extractedContent: List[ExtractedContent],
|
extractedContent: List[ContentExtracted],
|
||||||
aiResults: List[str],
|
aiResults: List[str],
|
||||||
strategy: MergeStrategy
|
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:
|
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
|
aiResults: List of AI response strings, one per chunk
|
||||||
strategy: Merge strategy configuration (dict or MergeStrategy object)
|
strategy: Merge strategy configuration (dict or MergeStrategy object)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Single ExtractedContent with merged AI results
|
Single ContentExtracted with merged AI results
|
||||||
"""
|
"""
|
||||||
logger.debug(f"=== MERGING AI RESULTS ===")
|
logger.debug(f"=== MERGING AI RESULTS ===")
|
||||||
logger.debug(f"Extracted content: {len(extractedContent)} documents")
|
logger.debug(f"Extracted content: {len(extractedContent)} documents")
|
||||||
|
|
@ -150,8 +150,8 @@ class ExtractionService:
|
||||||
# Default to concatenate
|
# Default to concatenate
|
||||||
mergedParts = self._mergeConcatenate(allParts, aiResultParts, mergeStrategy)
|
mergedParts = self._mergeConcatenate(allParts, aiResultParts, mergeStrategy)
|
||||||
|
|
||||||
# Create final ExtractedContent
|
# Create final ContentExtracted
|
||||||
mergedContent = ExtractedContent(
|
mergedContent = ContentExtracted(
|
||||||
id=f"merged_{uuid.uuid4()}",
|
id=f"merged_{uuid.uuid4()}",
|
||||||
parts=mergedParts
|
parts=mergedParts
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ from typing import Any, Dict, List
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from modules.datamodels.datamodelExtraction import ExtractedContent, ContentPart
|
from modules.datamodels.datamodelExtraction import ContentExtracted, ContentPart
|
||||||
from .subUtils import makeId
|
from .subUtils import makeId
|
||||||
from .subRegistry import ExtractorRegistry, ChunkerRegistry
|
from .subRegistry import ExtractorRegistry, ChunkerRegistry
|
||||||
from .merging.text_merger import TextMerger
|
from .merging.text_merger import TextMerger
|
||||||
|
|
@ -55,7 +55,7 @@ def _mergeParts(parts: List[ContentPart], mergeStrategy: Dict[str, Any]) -> List
|
||||||
return merged_parts
|
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)
|
extractor = extractorRegistry.resolve(mimeType, fileName)
|
||||||
if extractor is None:
|
if extractor is None:
|
||||||
# fallback: single binary part
|
# fallback: single binary part
|
||||||
|
|
@ -68,7 +68,7 @@ def runExtraction(extractorRegistry: ExtractorRegistry, chunkerRegistry: Chunker
|
||||||
data="",
|
data="",
|
||||||
metadata={"warning": "No extractor registered"}
|
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})
|
parts = extractor.extract(documentBytes, {"fileName": fileName, "mimeType": mimeType, "options": options})
|
||||||
|
|
||||||
|
|
@ -119,7 +119,7 @@ def runExtraction(extractorRegistry: ExtractorRegistry, chunkerRegistry: Chunker
|
||||||
except Exception as _e:
|
except Exception as _e:
|
||||||
logger.debug(f"Debug dump skipped: {_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]:
|
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
|
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.
|
Apply AI processing if requested in options.
|
||||||
This is a placeholder for actual AI integration.
|
This is a placeholder for actual AI integration.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import uuid
|
||||||
from typing import Dict, Any, List, Optional
|
from typing import Dict, Any, List, Optional
|
||||||
from modules.datamodels.datamodelUam import User, UserConnection
|
from modules.datamodels.datamodelUam import User, UserConnection
|
||||||
from modules.datamodels.datamodelChat import ChatDocument, ChatMessage
|
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.serviceExtraction.mainServiceExtraction import ExtractionService
|
||||||
from modules.services.serviceGeneration.subDocumentUtility import getFileExtension, getMimeTypeFromExtension, detectContentTypeFromData
|
from modules.services.serviceGeneration.subDocumentUtility import getFileExtension, getMimeTypeFromExtension, detectContentTypeFromData
|
||||||
from modules.shared.timezoneUtils import get_utc_timestamp
|
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 datetime import datetime, UTC
|
||||||
|
|
||||||
from modules.workflows.methods.methodBase import MethodBase, action
|
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.datamodelAi import AiCallOptions, OperationType, Priority
|
||||||
from modules.datamodels.datamodelChat import ChatDocument
|
from modules.datamodels.datamodelChat import ChatDocument
|
||||||
from modules.datamodels.datamodelWeb import WebResearchRequest, WebResearchOptions
|
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
|
# Parse JSON response from AI with streaming support
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
from modules.datamodels.datamodelWorkflow import ActionDocument
|
from modules.datamodels.datamodelChat import ActionDocument
|
||||||
|
|
||||||
action_documents = []
|
action_documents = []
|
||||||
all_data_chunks = [] # Store all data chunks for merging
|
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 datetime import datetime, UTC
|
||||||
|
|
||||||
from modules.workflows.methods.methodBase import MethodBase, action
|
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.datamodelChat import ChatDocument
|
||||||
from modules.datamodels.datamodelAi import AiCallOptions, OperationType, Priority
|
from modules.datamodels.datamodelAi import AiCallOptions, OperationType, Priority
|
||||||
|
|
||||||
|
|
@ -136,7 +136,7 @@ class MethodDocument(MethodBase):
|
||||||
action_documents = []
|
action_documents = []
|
||||||
|
|
||||||
for i, chatDocument in enumerate(chatDocuments):
|
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 = ""
|
text_content = ""
|
||||||
try:
|
try:
|
||||||
ec = all_extracted_content[i] if i < len(all_extracted_content) else None
|
ec = all_extracted_content[i] if i < len(all_extracted_content) else None
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import uuid
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from modules.workflows.methods.methodBase import MethodBase, action
|
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.datamodelAi import AiCallOptions, OperationType, Priority, AiCallRequest
|
||||||
from modules.datamodels.datamodelChat import ChatDocument
|
from modules.datamodels.datamodelChat import ChatDocument
|
||||||
from modules.datamodels.datamodelUam import ConnectionStatus
|
from modules.datamodels.datamodelUam import ConnectionStatus
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import aiohttp
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from modules.workflows.methods.methodBase import MethodBase, action
|
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__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict, Any, List
|
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.datamodels.datamodelChat import ChatWorkflow
|
||||||
from modules.workflows.processing.shared.methodDiscovery import methods
|
from modules.workflows.processing.shared.methodDiscovery import methods
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@ class ActionExecutor:
|
||||||
logger.error(f"Error executing compound action {compoundActionName}: {str(e)}")
|
logger.error(f"Error executing compound action {compoundActionName}: {str(e)}")
|
||||||
raise
|
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:
|
taskIndex: int = None, actionIndex: int = None, totalActions: int = None) -> ActionResult:
|
||||||
"""Execute a single action and return ActionResult with enhanced document processing"""
|
"""Execute a single action and return ActionResult with enhanced document processing"""
|
||||||
try:
|
try:
|
||||||
|
|
@ -199,7 +199,7 @@ class ActionExecutor:
|
||||||
# Join all document results with separators
|
# Join all document results with separators
|
||||||
return "\n\n---\n\n".join(resultParts) if resultParts else ""
|
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):
|
taskStep: TaskStep, taskIndex: int, actionIndex: int, totalActions: int):
|
||||||
"""Create action completion message with documents (generic)"""
|
"""Create action completion message with documents (generic)"""
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict, Any, Optional, List
|
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
|
from modules.datamodels.datamodelChat import ChatWorkflow
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict, Any
|
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.datamodels.datamodelAi import AiCallOptions, OperationType, ProcessingMode, Priority
|
||||||
from modules.workflows.processing.shared.promptGenerationTaskplan import (
|
from modules.workflows.processing.shared.promptGenerationTaskplan import (
|
||||||
createTaskPlanningPromptTemplate
|
createTaskPlanningPromptTemplate
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ import json
|
||||||
import logging
|
import logging
|
||||||
import uuid
|
import uuid
|
||||||
from typing import List, Dict, Any
|
from typing import List, Dict, Any
|
||||||
from modules.datamodels.datamodelWorkflow import (
|
from modules.datamodels.datamodelChat import (
|
||||||
TaskStep, TaskContext, TaskResult, TaskAction, TaskStatus,
|
TaskStep, TaskContext, TaskResult, ActionItem, TaskStatus,
|
||||||
ActionResult, ReviewResult, ReviewContext
|
ActionResult, ReviewResult, ReviewContext
|
||||||
)
|
)
|
||||||
from modules.datamodels.datamodelChat import ChatWorkflow
|
from modules.datamodels.datamodelChat import ChatWorkflow
|
||||||
|
|
@ -26,8 +26,8 @@ class ActionplanMode(BaseMode):
|
||||||
def __init__(self, services, workflow):
|
def __init__(self, services, workflow):
|
||||||
super().__init__(services, workflow)
|
super().__init__(services, workflow)
|
||||||
|
|
||||||
async def generateTaskActions(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
async def generateActionItems(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
||||||
previousResults: List = None, enhancedContext: TaskContext = None) -> List[TaskAction]:
|
previousResults: List = None, enhancedContext: TaskContext = None) -> List[ActionItem]:
|
||||||
"""Generate actions for a given task step using batch planning approach"""
|
"""Generate actions for a given task step using batch planning approach"""
|
||||||
try:
|
try:
|
||||||
# Check workflow status before generating actions
|
# Check workflow status before generating actions
|
||||||
|
|
@ -176,7 +176,7 @@ class ActionplanMode(BaseMode):
|
||||||
logger.error("Generated actions failed validation")
|
logger.error("Generated actions failed validation")
|
||||||
raise Exception("AI-generated actions failed validation - AI is required for action generation")
|
raise Exception("AI-generated actions failed validation - AI is required for action generation")
|
||||||
|
|
||||||
# Convert to TaskAction objects
|
# Convert to ActionItem objects
|
||||||
taskActions = []
|
taskActions = []
|
||||||
for i, a in enumerate(actions):
|
for i, a in enumerate(actions):
|
||||||
if not isinstance(a, dict):
|
if not isinstance(a, dict):
|
||||||
|
|
@ -193,7 +193,7 @@ class ActionplanMode(BaseMode):
|
||||||
# Old separate format: method + action fields
|
# Old separate format: method + action fields
|
||||||
method_name = a.get('method', 'unknown')
|
method_name = a.get('method', 'unknown')
|
||||||
|
|
||||||
taskAction = self._createTaskAction({
|
taskAction = self._createActionItem({
|
||||||
"execMethod": method_name,
|
"execMethod": method_name,
|
||||||
"execAction": action_name,
|
"execAction": action_name,
|
||||||
"execParameters": a.get('parameters', {}),
|
"execParameters": a.get('parameters', {}),
|
||||||
|
|
@ -207,7 +207,7 @@ class ActionplanMode(BaseMode):
|
||||||
if taskAction:
|
if taskAction:
|
||||||
taskActions.append(taskAction)
|
taskActions.append(taskAction)
|
||||||
else:
|
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]
|
validActions = [ta for ta in taskActions if ta]
|
||||||
|
|
||||||
|
|
@ -216,7 +216,7 @@ class ActionplanMode(BaseMode):
|
||||||
|
|
||||||
return validActions
|
return validActions
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error in generateTaskActions: {str(e)}")
|
logger.error(f"Error in generateActionItems: {str(e)}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -250,7 +250,7 @@ class ActionplanMode(BaseMode):
|
||||||
if retryContext:
|
if retryContext:
|
||||||
retryContext.retry_count = attempt + 1
|
retryContext.retry_count = attempt + 1
|
||||||
|
|
||||||
actions = await self.generateTaskActions(taskStep, workflow,
|
actions = await self.generateActionItems(taskStep, workflow,
|
||||||
previousResults=retryContext.previous_results,
|
previousResults=retryContext.previous_results,
|
||||||
enhancedContext=retryContext)
|
enhancedContext=retryContext)
|
||||||
|
|
||||||
|
|
@ -415,7 +415,7 @@ class ActionplanMode(BaseMode):
|
||||||
error="Task failed after all retries."
|
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:
|
actionResults: List[ActionResult], workflow: ChatWorkflow) -> ReviewResult:
|
||||||
"""Review task completion and determine success/failure/retry"""
|
"""Review task completion and determine success/failure/retry"""
|
||||||
try:
|
try:
|
||||||
|
|
@ -562,7 +562,7 @@ class ActionplanMode(BaseMode):
|
||||||
quality_score=0
|
quality_score=0
|
||||||
)
|
)
|
||||||
|
|
||||||
def _createTaskAction(self, actionData: Dict[str, Any]) -> TaskAction:
|
def _createActionItem(self, actionData: Dict[str, Any]) -> ActionItem:
|
||||||
"""Creates a new task action"""
|
"""Creates a new task action"""
|
||||||
try:
|
try:
|
||||||
# Ensure ID is present
|
# Ensure ID is present
|
||||||
|
|
@ -584,14 +584,14 @@ class ActionplanMode(BaseMode):
|
||||||
if "execParameters" not in actionData:
|
if "execParameters" not in actionData:
|
||||||
actionData["execParameters"] = {}
|
actionData["execParameters"] = {}
|
||||||
|
|
||||||
# Use generic field separation based on TaskAction model
|
# Use generic field separation based on ActionItem model
|
||||||
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(TaskAction, actionData)
|
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(ActionItem, actionData)
|
||||||
|
|
||||||
# Create action in database
|
# Create action in database
|
||||||
createdAction = self.services.interfaceDbChat.db.recordCreate(TaskAction, simpleFields)
|
createdAction = self.services.interfaceDbChat.db.recordCreate(ActionItem, simpleFields)
|
||||||
|
|
||||||
# Convert to TaskAction model
|
# Convert to ActionItem model
|
||||||
return TaskAction(
|
return ActionItem(
|
||||||
id=createdAction["id"],
|
id=createdAction["id"],
|
||||||
execMethod=createdAction["execMethod"],
|
execMethod=createdAction["execMethod"],
|
||||||
execAction=createdAction["execAction"],
|
execAction=createdAction["execAction"],
|
||||||
|
|
@ -704,7 +704,7 @@ class ActionplanMode(BaseMode):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error setting workflow totals: {str(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"""
|
"""Creates a new task action"""
|
||||||
try:
|
try:
|
||||||
import uuid
|
import uuid
|
||||||
|
|
@ -728,14 +728,14 @@ class ActionplanMode(BaseMode):
|
||||||
if "execParameters" not in actionData:
|
if "execParameters" not in actionData:
|
||||||
actionData["execParameters"] = {}
|
actionData["execParameters"] = {}
|
||||||
|
|
||||||
# Use generic field separation based on TaskAction model
|
# Use generic field separation based on ActionItem model
|
||||||
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(TaskAction, actionData)
|
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(ActionItem, actionData)
|
||||||
|
|
||||||
# Create action in database
|
# Create action in database
|
||||||
createdAction = self.services.interfaceDbChat.db.recordCreate(TaskAction, simpleFields)
|
createdAction = self.services.interfaceDbChat.db.recordCreate(ActionItem, simpleFields)
|
||||||
|
|
||||||
# Convert to TaskAction model
|
# Convert to ActionItem model
|
||||||
return TaskAction(
|
return ActionItem(
|
||||||
id=createdAction["id"],
|
id=createdAction["id"],
|
||||||
execMethod=createdAction["execMethod"],
|
execMethod=createdAction["execMethod"],
|
||||||
execAction=createdAction["execAction"],
|
execAction=createdAction["execAction"],
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
import logging
|
import logging
|
||||||
from typing import List, Dict, Any
|
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.datamodels.datamodelChat import ChatWorkflow
|
||||||
from modules.workflows.processing.core.taskPlanner import TaskPlanner
|
from modules.workflows.processing.core.taskPlanner import TaskPlanner
|
||||||
from modules.workflows.processing.core.actionExecutor import ActionExecutor
|
from modules.workflows.processing.core.actionExecutor import ActionExecutor
|
||||||
|
|
@ -46,8 +46,8 @@ class BaseMode(ABC):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def generateTaskActions(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
async def generateActionItems(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
||||||
previousResults: List = None, enhancedContext: TaskContext = None) -> List[TaskAction]:
|
previousResults: List = None, enhancedContext: TaskContext = None) -> List[ActionItem]:
|
||||||
"""Generate actions for a task step - must be implemented by concrete modes"""
|
"""Generate actions for a task step - must be implemented by concrete modes"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ import re
|
||||||
import time
|
import time
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import List, Dict, Any
|
from typing import List, Dict, Any
|
||||||
from modules.datamodels.datamodelWorkflow import (
|
from modules.datamodels.datamodelChat import (
|
||||||
TaskStep, TaskContext, TaskResult, TaskAction, TaskStatus,
|
TaskStep, TaskContext, TaskResult, ActionItem, TaskStatus,
|
||||||
ActionResult
|
ActionResult
|
||||||
)
|
)
|
||||||
from modules.datamodels.datamodelChat import ChatWorkflow
|
from modules.datamodels.datamodelChat import ChatWorkflow
|
||||||
|
|
@ -38,8 +38,8 @@ class ReactMode(BaseMode):
|
||||||
self.currentIntent = None
|
self.currentIntent = None
|
||||||
# Placeholder service no longer used; prompts are generated directly
|
# Placeholder service no longer used; prompts are generated directly
|
||||||
|
|
||||||
async def generateTaskActions(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
async def generateActionItems(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
||||||
previousResults: List = None, enhancedContext: TaskContext = None) -> List[TaskAction]:
|
previousResults: List = None, enhancedContext: TaskContext = None) -> List[ActionItem]:
|
||||||
"""React mode doesn't use batch action generation - actions are generated iteratively"""
|
"""React mode doesn't use batch action generation - actions are generated iteratively"""
|
||||||
# React mode generates actions one at a time in the execution loop
|
# React mode generates actions one at a time in the execution loop
|
||||||
return []
|
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):
|
if 'language' not in parameters and hasattr(self.services, 'user') and getattr(self.services.user, 'language', None):
|
||||||
parameters['language'] = self.services.user.language
|
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)
|
currentRound = getattr(self.workflow, 'currentRound', 0)
|
||||||
currentTask = getattr(self.workflow, 'currentTask', 0)
|
currentTask = getattr(self.workflow, 'currentTask', 0)
|
||||||
resultLabel = f"round{currentRound}_task{currentTask}_action{stepIndex}_results"
|
resultLabel = f"round{currentRound}_task{currentTask}_action{stepIndex}_results"
|
||||||
|
|
||||||
taskAction = self._createTaskAction({
|
taskAction = self._createActionItem({
|
||||||
"execMethod": methodName,
|
"execMethod": methodName,
|
||||||
"execAction": actionName,
|
"execAction": actionName,
|
||||||
"execParameters": parameters,
|
"execParameters": parameters,
|
||||||
|
|
@ -463,7 +463,7 @@ class ReactMode(BaseMode):
|
||||||
async def _refineDecide(self, context: TaskContext, observation: Dict[str, Any]) -> Dict[str, Any]:
|
async def _refineDecide(self, context: TaskContext, observation: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
"""Refine: decide continue or stop, with reason"""
|
"""Refine: decide continue or stop, with reason"""
|
||||||
# Create proper ReviewContext for extractReviewContent
|
# Create proper ReviewContext for extractReviewContent
|
||||||
from modules.datamodels.datamodelWorkflow import ReviewContext
|
from modules.datamodels.datamodelChat import ReviewContext
|
||||||
reviewContext = ReviewContext(
|
reviewContext = ReviewContext(
|
||||||
task_step=context.task_step,
|
task_step=context.task_step,
|
||||||
task_actions=[],
|
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)}")
|
logger.error(f"Error generating action result message: {str(e)}")
|
||||||
return f"{method}.{actionName} action completed"
|
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"""
|
"""Creates a new task action for React mode"""
|
||||||
try:
|
try:
|
||||||
import uuid
|
import uuid
|
||||||
|
|
@ -686,14 +686,14 @@ Return only the user-friendly message, no technical details."""
|
||||||
if "execParameters" not in actionData:
|
if "execParameters" not in actionData:
|
||||||
actionData["execParameters"] = {}
|
actionData["execParameters"] = {}
|
||||||
|
|
||||||
# Use generic field separation based on TaskAction model
|
# Use generic field separation based on ActionItem model
|
||||||
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(TaskAction, actionData)
|
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(ActionItem, actionData)
|
||||||
|
|
||||||
# Create action in database
|
# Create action in database
|
||||||
createdAction = self.services.interfaceDbChat.db.recordCreate(TaskAction, simpleFields)
|
createdAction = self.services.interfaceDbChat.db.recordCreate(ActionItem, simpleFields)
|
||||||
|
|
||||||
# Convert to TaskAction model
|
# Convert to ActionItem model
|
||||||
return TaskAction(
|
return ActionItem(
|
||||||
id=createdAction["id"],
|
id=createdAction["id"],
|
||||||
execMethod=createdAction["execMethod"],
|
execMethod=createdAction["execMethod"],
|
||||||
execAction=createdAction["execAction"],
|
execAction=createdAction["execAction"],
|
||||||
|
|
@ -753,7 +753,7 @@ Return only the user-friendly message, no technical details."""
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error updating workflow before executing action: {str(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"""
|
"""Creates a new task action for React mode"""
|
||||||
try:
|
try:
|
||||||
import uuid
|
import uuid
|
||||||
|
|
@ -777,14 +777,14 @@ Return only the user-friendly message, no technical details."""
|
||||||
if "execParameters" not in actionData:
|
if "execParameters" not in actionData:
|
||||||
actionData["execParameters"] = {}
|
actionData["execParameters"] = {}
|
||||||
|
|
||||||
# Use generic field separation based on TaskAction model
|
# Use generic field separation based on ActionItem model
|
||||||
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(TaskAction, actionData)
|
simpleFields, objectFields = self.services.interfaceDbChat._separate_object_fields(ActionItem, actionData)
|
||||||
|
|
||||||
# Create action in database
|
# Create action in database
|
||||||
createdAction = self.services.interfaceDbChat.db.recordCreate(TaskAction, simpleFields)
|
createdAction = self.services.interfaceDbChat.db.recordCreate(ActionItem, simpleFields)
|
||||||
|
|
||||||
# Convert to TaskAction model
|
# Convert to ActionItem model
|
||||||
return TaskAction(
|
return ActionItem(
|
||||||
id=createdAction["id"],
|
id=createdAction["id"],
|
||||||
execMethod=createdAction["execMethod"],
|
execMethod=createdAction["execMethod"],
|
||||||
execAction=createdAction["execAction"],
|
execAction=createdAction["execAction"],
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
import logging
|
import logging
|
||||||
from typing import List
|
from typing import List
|
||||||
from datetime import datetime, UTC
|
from datetime import datetime, UTC
|
||||||
from modules.datamodels.datamodelWorkflow import TaskStep
|
from modules.datamodels.datamodelChat import TaskStep
|
||||||
from modules.datamodels.datamodelWorkflow import ActionResult
|
from modules.datamodels.datamodelChat import ActionResult
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import importlib
|
||||||
import pkgutil
|
import pkgutil
|
||||||
import inspect
|
import inspect
|
||||||
from typing import Any, Dict, List
|
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
|
from modules.workflows.methods.methodBase import MethodBase
|
||||||
|
|
||||||
# Set up logger
|
# Set up logger
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ Handles prompt templates and extraction functions for actionplan mode action han
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict, Any, List
|
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 (
|
from modules.workflows.processing.shared.placeholderFactory import (
|
||||||
extractUserPrompt,
|
extractUserPrompt,
|
||||||
extractAvailableDocumentsSummary,
|
extractAvailableDocumentsSummary,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Handles prompt templates for react mode action handling.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Any, List
|
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 (
|
from modules.workflows.processing.shared.placeholderFactory import (
|
||||||
extractUserPrompt,
|
extractUserPrompt,
|
||||||
extractUserLanguage,
|
extractUserLanguage,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ Handles prompt templates and extraction functions for task planning phase.
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict, Any, List
|
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 (
|
from modules.workflows.processing.shared.placeholderFactory import (
|
||||||
extractUserPrompt,
|
extractUserPrompt,
|
||||||
extractAvailableDocumentsSummary,
|
extractAvailableDocumentsSummary,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict, Any, Optional, List
|
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.datamodels.datamodelChat import ChatWorkflow
|
||||||
from modules.workflows.processing.modes.modeBase import BaseMode
|
from modules.workflows.processing.modes.modeBase import BaseMode
|
||||||
from modules.workflows.processing.modes.modeActionplan import ActionplanMode
|
from modules.workflows.processing.modes.modeActionplan import ActionplanMode
|
||||||
|
|
@ -84,7 +84,7 @@ class WorkflowProcessor:
|
||||||
logger.error(f"Error in executeTask: {str(e)}")
|
logger.error(f"Error in executeTask: {str(e)}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
async def generateTaskActions(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
async def generateActionItems(self, taskStep: TaskStep, workflow: ChatWorkflow,
|
||||||
previousResults: List = None, enhancedContext: TaskContext = None) -> List:
|
previousResults: List = None, enhancedContext: TaskContext = None) -> List:
|
||||||
"""Generate actions for a task step using the appropriate mode"""
|
"""Generate actions for a task step using the appropriate mode"""
|
||||||
try:
|
try:
|
||||||
|
|
@ -96,9 +96,9 @@ class WorkflowProcessor:
|
||||||
logger.info(f"Mode: {workflow.workflowMode}")
|
logger.info(f"Mode: {workflow.workflowMode}")
|
||||||
|
|
||||||
# Delegate to the appropriate mode
|
# 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:
|
except Exception as e:
|
||||||
logger.error(f"Error in generateTaskActions: {str(e)}")
|
logger.error(f"Error in generateActionItems: {str(e)}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def updateWorkflowAfterTaskPlanCreated(self, totalTasks: int):
|
def updateWorkflowAfterTaskPlanCreated(self, totalTasks: int):
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,9 @@ from modules.datamodels.datamodelChat import (
|
||||||
UserInputRequest,
|
UserInputRequest,
|
||||||
ChatMessage,
|
ChatMessage,
|
||||||
ChatWorkflow,
|
ChatWorkflow,
|
||||||
ChatDocument,
|
ChatDocument
|
||||||
WorkflowResult
|
|
||||||
)
|
)
|
||||||
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.workflows.processing.workflowProcessor import WorkflowProcessor, WorkflowStoppedException
|
||||||
from modules.shared.timezoneUtils import get_utc_timestamp
|
from modules.shared.timezoneUtils import get_utc_timestamp
|
||||||
|
|
||||||
|
|
@ -160,8 +159,8 @@ class WorkflowManager:
|
||||||
self.workflowProcessor = WorkflowProcessor(self.services, workflow)
|
self.workflowProcessor = WorkflowProcessor(self.services, workflow)
|
||||||
message = await self._sendFirstMessage(userInput, workflow)
|
message = await self._sendFirstMessage(userInput, workflow)
|
||||||
task_plan = await self._planTasks(userInput, workflow)
|
task_plan = await self._planTasks(userInput, workflow)
|
||||||
workflow_result = await self._executeTasks(task_plan, workflow)
|
await self._executeTasks(task_plan, workflow)
|
||||||
await self._processWorkflowResults(workflow, workflow_result, message)
|
await self._processWorkflowResults(workflow, message)
|
||||||
|
|
||||||
except WorkflowStoppedException:
|
except WorkflowStoppedException:
|
||||||
self._handleWorkflowStop(workflow)
|
self._handleWorkflowStop(workflow)
|
||||||
|
|
@ -359,8 +358,8 @@ class WorkflowManager:
|
||||||
logger.info(f"Executing workflow mode={workflow_mode} with {len(task_plan.tasks)} tasks")
|
logger.info(f"Executing workflow mode={workflow_mode} with {len(task_plan.tasks)} tasks")
|
||||||
return task_plan
|
return task_plan
|
||||||
|
|
||||||
async def _executeTasks(self, task_plan, workflow: ChatWorkflow) -> WorkflowResult:
|
async def _executeTasks(self, task_plan, workflow: ChatWorkflow) -> None:
|
||||||
"""Execute all tasks in the task plan"""
|
"""Execute all tasks in the task plan and update workflow status."""
|
||||||
handling = self.workflowProcessor
|
handling = self.workflowProcessor
|
||||||
total_tasks = len(task_plan.tasks)
|
total_tasks = len(task_plan.tasks)
|
||||||
all_task_results: List = []
|
all_task_results: List = []
|
||||||
|
|
@ -404,16 +403,12 @@ class WorkflowManager:
|
||||||
if task_result.success and task_result.feedback:
|
if task_result.success and task_result.feedback:
|
||||||
previous_results.append(task_result.feedback)
|
previous_results.append(task_result.feedback)
|
||||||
|
|
||||||
return WorkflowResult(
|
# Mark workflow as completed; error/stop cases update status elsewhere
|
||||||
status="completed",
|
workflow.status = "completed"
|
||||||
completed_tasks=len(all_task_results),
|
return None
|
||||||
total_tasks=total_tasks,
|
|
||||||
execution_time=0.0,
|
|
||||||
final_results_count=len(all_task_results)
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _processWorkflowResults(self, workflow: ChatWorkflow, workflow_result: WorkflowResult, initial_message: ChatMessage) -> None:
|
async def _processWorkflowResults(self, workflow: ChatWorkflow, initial_message: ChatMessage) -> None:
|
||||||
"""Process workflow results and create appropriate messages"""
|
"""Process workflow results based on workflow status and create appropriate messages"""
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
self.workflowProcessor._checkWorkflowStopped(workflow)
|
self.workflowProcessor._checkWorkflowStopped(workflow)
|
||||||
|
|
@ -451,7 +446,7 @@ class WorkflowManager:
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
|
||||||
if workflow_result.status == 'stopped':
|
if workflow.status == 'stopped':
|
||||||
# Create stopped message
|
# Create stopped message
|
||||||
stopped_message = {
|
stopped_message = {
|
||||||
"workflowId": workflow.id,
|
"workflowId": workflow.id,
|
||||||
|
|
@ -493,12 +488,12 @@ class WorkflowManager:
|
||||||
"progress": 100
|
"progress": 100
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
elif workflow_result.status == 'failed':
|
elif workflow.status == 'failed':
|
||||||
# Create error message
|
# Create error message
|
||||||
error_message = {
|
error_message = {
|
||||||
"workflowId": workflow.id,
|
"workflowId": workflow.id,
|
||||||
"role": "assistant",
|
"role": "assistant",
|
||||||
"message": f"Workflow failed: {workflow_result.error or 'Unknown error'}",
|
"message": f"Workflow failed: {'Unknown error'}",
|
||||||
"status": "last",
|
"status": "last",
|
||||||
"sequenceNr": len(workflow.messages) + 1,
|
"sequenceNr": len(workflow.messages) + 1,
|
||||||
"publishedAt": self.services.utils.getUtcTimestamp(),
|
"publishedAt": self.services.utils.getUtcTimestamp(),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue