diff --git a/modules/interfaces/interfaceDbApp.py b/modules/interfaces/interfaceDbApp.py index bb75e972..e4384882 100644 --- a/modules/interfaces/interfaceDbApp.py +++ b/modules/interfaces/interfaceDbApp.py @@ -1266,11 +1266,27 @@ class AppObjects: return [] def getUserConnectionById(self, connectionId: str) -> Optional[UserConnection]: - """Get a single UserConnection by ID.""" + """Get a single UserConnection by ID or by reference string (connection:authority:username).""" try: + # Try direct UUID lookup first connections = self.db.getRecordset( UserConnection, recordFilter={"id": connectionId} ) + + # Fallback: parse "connection:authority:username" format from AI agent + if not connections and connectionId.startswith("connection:"): + parts = connectionId.split(":", 2) + if len(parts) >= 3: + authority = parts[1] + username = parts[2] + allConns = self.db.getRecordset(UserConnection, recordFilter={"externalUsername": username}) + for c in (allConns or []): + a = c.get("authority", "") + aVal = a.value if hasattr(a, "value") else str(a) + if aVal == authority: + connections = [c] + break + if connections: conn_dict = connections[0] return UserConnection( diff --git a/modules/serviceCenter/services/serviceAgent/actionToolAdapter.py b/modules/serviceCenter/services/serviceAgent/actionToolAdapter.py index 815be871..0026fa23 100644 --- a/modules/serviceCenter/services/serviceAgent/actionToolAdapter.py +++ b/modules/serviceCenter/services/serviceAgent/actionToolAdapter.py @@ -135,6 +135,11 @@ def _createDispatchHandler(actionExecutor, methodName: str, actionName: str): """Create an async handler that dispatches to the ActionExecutor.""" async def _handler(args: Dict[str, Any], context: Dict[str, Any]) -> ToolResult: try: + if context: + if "featureInstanceId" not in args and context.get("featureInstanceId"): + args["featureInstanceId"] = context["featureInstanceId"] + if "mandateId" not in args and context.get("mandateId"): + args["mandateId"] = context["mandateId"] result = await actionExecutor.executeAction(methodName, actionName, args) data = _formatActionResult(result) return ToolResult( diff --git a/modules/serviceCenter/services/serviceAgent/coreTools/_connectionTools.py b/modules/serviceCenter/services/serviceAgent/coreTools/_connectionTools.py index e4018014..7073429f 100644 --- a/modules/serviceCenter/services/serviceAgent/coreTools/_connectionTools.py +++ b/modules/serviceCenter/services/serviceAgent/coreTools/_connectionTools.py @@ -44,12 +44,12 @@ def _registerConnectionTools(registry: ToolRegistry, services): return ToolResult(toolCallId="", toolName="listConnections", success=True, data="No connections available.") lines = [] for conn in connections: + connId = conn.get("id", "") if isinstance(conn, dict) else getattr(conn, "id", "") authority = conn.get("authority", "?") if isinstance(conn, dict) else getattr(conn, "authority", "?") authorityVal = authority.value if hasattr(authority, "value") else str(authority) username = conn.get("externalUsername", "") if isinstance(conn, dict) else getattr(conn, "externalUsername", "") email = conn.get("externalEmail", "") if isinstance(conn, dict) else getattr(conn, "externalEmail", "") - ref = f"connection:{authorityVal}:{username}" - lines.append(f"- {ref} ({email})") + lines.append(f"- connectionId: {connId} | {authorityVal} | {username} ({email})") return ToolResult(toolCallId="", toolName="listConnections", success=True, data="\n".join(lines)) except Exception as e: return ToolResult(toolCallId="", toolName="listConnections", success=False, error=str(e)) @@ -137,7 +137,7 @@ def _registerConnectionTools(registry: ToolRegistry, services): return ToolResult(toolCallId="", toolName="sendMail", success=False, error=str(e)) _connToolParams = { - "connectionId": {"type": "string", "description": "UserConnection ID"}, + "connectionId": {"type": "string", "description": "UserConnection UUID (from listConnections output, e.g. '3fa85f64-...')"}, "service": {"type": "string", "description": "Service name (sharepoint, outlook, drive, etc.)"}, } @@ -177,7 +177,7 @@ def _registerConnectionTools(registry: ToolRegistry, services): parameters={ "type": "object", "properties": { - "connectionId": {"type": "string", "description": "UserConnection ID"}, + "connectionId": {"type": "string", "description": "UserConnection UUID (from listConnections output)"}, "to": {"type": "array", "items": {"type": "string"}, "description": "Recipient email addresses"}, "subject": {"type": "string", "description": "Email subject"}, "body": {"type": "string", "description": "Email body — plain text or HTML markup"}, diff --git a/modules/serviceCenter/services/serviceAgent/mainServiceAgent.py b/modules/serviceCenter/services/serviceAgent/mainServiceAgent.py index b24d9fcb..3638ccf6 100644 --- a/modules/serviceCenter/services/serviceAgent/mainServiceAgent.py +++ b/modules/serviceCenter/services/serviceAgent/mainServiceAgent.py @@ -267,6 +267,8 @@ class AgentService: registerCoreTools(registry, self.services) try: + from modules.workflows.processing.shared.methodDiscovery import discoverMethods + discoverMethods(self.services) from modules.workflows.processing.core.actionExecutor import ActionExecutor actionExecutor = ActionExecutor(self.services) adapter = ActionToolAdapter(actionExecutor) @@ -293,10 +295,14 @@ class AgentService: userConnections: List[str] = [] try: - connectionService = self._getService("connection") - if connectionService and hasattr(connectionService, "getConnections"): - connections = connectionService.getConnections() or [] - userConnections = [c.get("authority", "") for c in connections if c.get("authority")] + chatService = self.services.chat if hasattr(self.services, "chat") else None + if chatService and hasattr(chatService, "getUserConnections"): + connections = chatService.getUserConnections() or [] + for c in connections: + authority = c.get("authority", "") if isinstance(c, dict) else getattr(c, "authority", "") + authorityVal = authority.value if hasattr(authority, "value") else str(authority) + if authorityVal: + userConnections.append(authorityVal) except Exception as e: logger.debug("Could not resolve user connections for toolbox activation: %s", e) @@ -370,13 +376,23 @@ class AgentService: if registry.isValidTool(toolName): activatedCount += 1 continue + try: + from modules.serviceCenter.services.serviceAgent.coreTools import registerCoreTools + registerCoreTools(registry, self.services) + if registry.isValidTool(toolName): + activatedCount += 1 + logger.info("requestToolbox: re-registered tool '%s' (core) from toolbox '%s'", toolName, toolboxId) + continue + except Exception: + pass try: from modules.serviceCenter.services.serviceAgent.actionToolAdapter import ActionToolAdapter - adapter = ActionToolAdapter(self._getService("actionExecutor")) + from modules.workflows.processing.core.actionExecutor import ActionExecutor + adapter = ActionToolAdapter(ActionExecutor(self.services)) adapter.registerAll(registry) if registry.isValidTool(toolName): activatedCount += 1 - logger.info("requestToolbox: re-registered tool '%s' from toolbox '%s'", toolName, toolboxId) + logger.info("requestToolbox: re-registered tool '%s' (action) from toolbox '%s'", toolName, toolboxId) else: logger.warning("requestToolbox: tool '%s' from toolbox '%s' could not be registered", toolName, toolboxId) except Exception as regErr: diff --git a/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py b/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py index 32440896..d05cfded 100644 --- a/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py +++ b/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py @@ -149,7 +149,7 @@ def _registerDefaultToolboxes() -> None: id="email", label="Email", description="Send emails or save as draft via Outlook (supports HTML body and file attachments). Use sendMail with draft=true for drafts.", - requiresConnection="microsoft", + requiresConnection="msft", isDefault=False, tools=[ "sendMail", @@ -159,7 +159,7 @@ def _registerDefaultToolboxes() -> None: id="sharepoint", label="SharePoint", description="Access SharePoint sites, lists, and files", - requiresConnection="microsoft", + requiresConnection="msft", isDefault=False, tools=[ "sharepoint_findDocuments", "sharepoint_readDocuments",