diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 000000000..7dcaea4dd --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,7 @@ +## 2024-05-23 - Chat Latency Optimization +**Learning:** Independent asynchronous operations (Embedding Generation + Vector Search vs User Context DB Queries) were being executed sequentially in the chat route and service, adding unnecessary latency. +**Action:** Always check for opportunities to use `Promise.all` when fetching multiple independent data sources for a request context. Parallelizing external API calls (Embeddings) with local DB queries is a high-impact optimization. + +## 2026-01-18 - Dashboard Latency Optimization +**Learning:** The dashboard endpoint was sequentially fetching user metrics *after* fetching global metrics, doubling the latency for logged-in users. +**Action:** Group all independent `Promise` returning functions in a single `Promise.all` block, even if some depend on conditional logic (use ternary operators to pass `Promise.resolve(undefined)` or similar). diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 000000000..f1766d577 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,19 @@ +## 2026-01-03 - [SSRF Protection] +**Vulnerability:** Found a potential Server-Side Request Forgery (SSRF) vulnerability in `backend/src/services/langchain/langgraph/step-nodes.ts` where user-provided URLs in `executeWebhookStep` were fetched without validation. +**Learning:** `fetch` calls in automation or webhook steps are prime candidates for SSRF if they accept arbitrary URLs. Developers might assume that because it's a "webhook", the user *should* be able to call anything, but internal network access must be restricted. +**Prevention:** Implemented a `validateWebUrl` utility that resolves DNS and checks against private IP ranges (IPv4 and IPv6). Applied this check before the `fetch` call. Also, using `dns.lookup` is necessary because simple string matching on hostname is insufficient due to DNS rebinding or different IP representations. + +## 2026-01-20 - [Auth Timing Attack Prevention] +**Vulnerability:** The login endpoint (`/api/auth/login`) was vulnerable to **User Enumeration** via **Timing Attack**. The code returned immediately if the user was not found (`!user`), but performed an expensive `bcrypt.compare` operation if the user existed. This timing difference allowed attackers to verify valid email addresses. +**Learning:** Authentication failures must take approximately the same amount of time regardless of whether the user exists or the password is incorrect. `bcrypt` is computationally expensive (by design), making the timing gap significant and easily measurable. +**Prevention:** Implemented **Constant Time Comparison** (or rather, "Equalized Time"). If the user is not found, the system now compares the provided password against a pre-calculated "dummy" hash (with the same cost factor). This ensures that every login attempt performs exactly one `bcrypt.compare` operation, masking the existence of the user. + +## 2025-10-24 - [Password Complexity Enforcement] +**Vulnerability:** The registration endpoint (`/api/auth/register`) allowed weak passwords (minimum 8 characters, but no complexity requirements). This increased susceptibility to brute-force and credential stuffing attacks. +**Learning:** Relying solely on length is insufficient. Zod schemas in `auth-simple.ts` were only checking `.min(8)`. +**Prevention:** Enhanced `registerSchema` in `backend/src/routes/auth-simple.ts` to enforce: 1 lowercase, 1 uppercase, 1 number, and max length of 100 characters (to prevent DoS). + +## 2026-02-23 - [XSS in Custom Markdown Parser] +**Vulnerability:** A Stored XSS vulnerability was identified in `src/components/preview/viewers/MarkdownViewer.tsx`. The component used a custom regex-based Markdown parser that failed to validate URL protocols in links, allowing payloads like `[click](javascript:alert(1))` to execute arbitrary JavaScript. +**Learning:** Custom regex parsers for complex formats like Markdown are notoriously prone to security bypasses. Validating input structure via regex is insufficient for preventing XSS in HTML output; context-aware sanitization is required. +**Prevention:** Integrated `DOMPurify` to sanitize the HTML output of the custom parser. Configured it to allow necessary tags and attributes (like `class` for styling) while stripping dangerous content (like `javascript:` URIs). diff --git a/backend/e2e-evidence/v4-2025-12-20/control-plane-stats.json b/backend/e2e-evidence/v4-2025-12-20/control-plane-stats.json new file mode 100644 index 000000000..27675277a --- /dev/null +++ b/backend/e2e-evidence/v4-2025-12-20/control-plane-stats.json @@ -0,0 +1,32 @@ +{ + "success": true, + "data": { + "v4Enabled": false, + "features": { + "agentFactory": true, + "tracing": true, + "memory": true, + "workflow": true, + "planning": true, + "reasoning": true, + "reflection": true, + "evaluation": true + }, + "stats": { + "agents": { + "cached": 1, + "maxCache": 50, + "hitRate": 0 + }, + "memory": { + "total": 0 + }, + "workflows": { + "cached": 5 + }, + "tracing": { + "spansLast7Days": 18 + } + } + } +} \ No newline at end of file diff --git a/backend/e2e-evidence/v4-2025-12-20/memory-search-results.json b/backend/e2e-evidence/v4-2025-12-20/memory-search-results.json new file mode 100644 index 000000000..f7201a5a1 --- /dev/null +++ b/backend/e2e-evidence/v4-2025-12-20/memory-search-results.json @@ -0,0 +1,133 @@ +{ + "memories": [ + { + "id": "a73c5de4-c66c-48e2-a476-462d98c44046", + "content": "Notei que usuários preferem respostas curtas", + "source_type": "conversation", + "metadata": { + "supermemory": { + "tags": [ + "general" + ], + "type": "general", + "savedAt": "2025-12-20T19:37:04.816Z", + "duration": "medium_term" + } + }, + "created_at": "2025-12-20T19:37:05.153Z" + }, + { + "id": "ccfddf04-23d2-4b49-9075-2093b009f1a1", + "content": "Acredito que Python é uma excelente linguagem para IA", + "source_type": "conversation", + "metadata": { + "supermemory": { + "tags": [ + "general" + ], + "type": "general", + "savedAt": "2025-12-20T19:37:03.161Z", + "duration": "medium_term" + } + }, + "created_at": "2025-12-20T19:37:03.498Z" + }, + { + "id": "02788d43-6175-4998-a331-70cfaf2679de", + "content": "Eu visitei o Rio de Janeiro em 2024", + "source_type": "conversation", + "metadata": { + "supermemory": { + "tags": [ + "general" + ], + "type": "general", + "savedAt": "2025-12-20T19:37:01.656Z", + "duration": "medium_term" + } + }, + "created_at": "2025-12-20T19:37:01.993Z" + }, + { + "id": "0236668b-2199-46e8-8232-134994b3f97a", + "content": "O Brasil é o maior país da América do Sul", + "source_type": "conversation", + "metadata": { + "supermemory": { + "tags": [ + "general" + ], + "type": "general", + "savedAt": "2025-12-20T19:37:00.090Z", + "duration": "medium_term" + } + }, + "created_at": "2025-12-20T19:37:00.427Z" + }, + { + "id": "4645b940-3d40-46ee-8987-a5b65a4725a7", + "content": "Teste rápido para research", + "source_type": "message", + "metadata": { + "type": "user_message", + "created_at": "2025-12-20T19:36:55.538031+00:00", + "auto_generated": true, + "conversation_id": "773fb453-17c9-4556-a36c-e383d754a804", + "original_message_id": "0163fe46-d551-4b8c-ab4e-6b2e6f04eae2" + }, + "created_at": "2025-12-20T19:36:55.538Z" + }, + { + "id": "440c5e90-9a61-4489-a8f1-4cd2935b8954", + "content": "Teste rápido para content_creator", + "source_type": "message", + "metadata": { + "type": "user_message", + "created_at": "2025-12-20T19:36:43.056398+00:00", + "auto_generated": true, + "conversation_id": "773fb453-17c9-4556-a36c-e383d754a804", + "original_message_id": "40324951-7afe-4f04-ab31-54f3827f9346" + }, + "created_at": "2025-12-20T19:36:43.056Z" + }, + { + "id": "e16d6075-d456-4294-9622-85f487ef46dc", + "content": "Teste rápido para goal_manager", + "source_type": "message", + "metadata": { + "type": "user_message", + "created_at": "2025-12-20T19:36:29.177213+00:00", + "auto_generated": true, + "conversation_id": "773fb453-17c9-4556-a36c-e383d754a804", + "original_message_id": "d7e45a5a-b582-428d-b7d8-11c345ef2432" + }, + "created_at": "2025-12-20T19:36:29.177Z" + }, + { + "id": "02bb5785-1ad5-4778-8bea-d3f5f09bcb60", + "content": "Teste rápido para task_manager", + "source_type": "message", + "metadata": { + "type": "user_message", + "created_at": "2025-12-20T19:36:17.003627+00:00", + "auto_generated": true, + "conversation_id": "773fb453-17c9-4556-a36c-e383d754a804", + "original_message_id": "ec72e6fe-17c7-4060-b315-152978f86091" + }, + "created_at": "2025-12-20T19:36:17.003Z" + }, + { + "id": "6749c6c7-3e42-401b-8b5b-cb75fbf1c0a8", + "content": "Olá, estou testando a V4. Responda brevemente.", + "source_type": "message", + "metadata": { + "type": "user_message", + "created_at": "2025-12-20T19:36:03.855881+00:00", + "auto_generated": true, + "conversation_id": "773fb453-17c9-4556-a36c-e383d754a804", + "original_message_id": "4f14be66-c156-4bca-a370-6578683db54c" + }, + "created_at": "2025-12-20T19:36:03.855Z" + } + ] +} \ No newline at end of file diff --git a/backend/e2e-evidence/v4-2025-12-20/research-agent-response.json b/backend/e2e-evidence/v4-2025-12-20/research-agent-response.json new file mode 100644 index 000000000..390acb38b --- /dev/null +++ b/backend/e2e-evidence/v4-2025-12-20/research-agent-response.json @@ -0,0 +1,27 @@ +{ + "agentUsed": "research", + "responseLength": 104, + "latency": 13569, + "metadata": { + "processingTime": 12376, + "memoryFirstTime": 0, + "routingTime": 0, + "executionTime": 2626, + "routingConfidence": 1, + "routingReasoning": "Agente forçado pela requisição", + "toolsAvailable": 12, + "toolsUsed": [], + "supermemoryMatches": 0, + "memoryFilterResult": { + "saved": false, + "type": "not_relevant", + "score": 0 + }, + "architecture": "v4-enhanced", + "traceId": "trace-1766259523094-fu0hmsfpm", + "architectureVersion": "v4", + "agent": "research", + "googleAIConfigured": true, + "intelligentRouting": true + } +} \ No newline at end of file diff --git a/backend/e2e-evidence/v4-2025-12-20/tracing-spans.json b/backend/e2e-evidence/v4-2025-12-20/tracing-spans.json new file mode 100644 index 000000000..44630d1f5 --- /dev/null +++ b/backend/e2e-evidence/v4-2025-12-20/tracing-spans.json @@ -0,0 +1,98 @@ +{ + "success": true, + "data": [ + { + "id": "82a450f2-0829-4d4d-837e-010eb231142a", + "spanType": "response", + "agentType": "general", + "output": "Erro de configuração: O modelo \"gemini-3-flash\" não está disponível. Verifique a configuração do modelo.", + "latencyMs": 2233, + "success": true, + "startedAt": "2025-12-20T19:37:17.649Z" + }, + { + "id": "e37f8e31-3720-4341-a461-55a9a3995d0c", + "spanType": "prompt", + "agentType": "general", + "input": "Teste de tracing V4", + "latencyMs": 1694, + "success": true, + "startedAt": "2025-12-20T19:37:16.283Z" + }, + { + "id": "528468b0-1372-4def-a145-17306054c7db", + "spanType": "router", + "agentType": null, + "input": "Teste de tracing V4", + "output": "Erro de configuração: O modelo \"gemini-3-flash\" não está disponível. Verifique a configuração do modelo.", + "latencyMs": 5794, + "success": true, + "startedAt": "2025-12-20T19:37:13.907Z" + }, + { + "id": "ccff860e-8923-4a49-b4d5-09716916e16b", + "spanType": "response", + "agentType": "research", + "output": "Erro de configuração: O modelo \"gemini-3-flash\" não está disponível. Verifique a configuração do modelo.", + "latencyMs": 1429, + "success": true, + "startedAt": "2025-12-20T19:36:52.747Z" + }, + { + "id": "1db40d25-e57d-4b8f-b243-2ed114897e62", + "spanType": "prompt", + "agentType": "research", + "input": "Teste rápido para research", + "latencyMs": 897, + "success": true, + "startedAt": "2025-12-20T19:36:51.318Z" + }, + { + "id": "821a5f89-b343-4134-8fb0-63617571ee2a", + "spanType": "router", + "agentType": null, + "input": "Teste rápido para research", + "output": "Erro de configuração: O modelo \"gemini-3-flash\" não está disponível. Verifique a configuração do modelo.", + "latencyMs": 2497, + "success": true, + "startedAt": "2025-12-20T19:36:50.783Z" + }, + { + "id": "ca9be6de-e372-48b3-9413-5954acdfddec", + "spanType": "response", + "agentType": "content_creator", + "output": "Erro de configuração: O modelo \"gemini-3-flash\" não está disponível. Verifique a configuração do modelo.", + "latencyMs": 2096, + "success": true, + "startedAt": "2025-12-20T19:36:40.311Z" + }, + { + "id": "8882160a-b048-47ad-aae4-9e9098bc89cf", + "spanType": "prompt", + "agentType": "content_creator", + "input": "Teste rápido para content_creator", + "latencyMs": 1562, + "success": true, + "startedAt": "2025-12-20T19:36:38.215Z" + }, + { + "id": "1f2d747f-4ffb-4e7a-a2a5-9eb2920381aa", + "spanType": "router", + "agentType": null, + "input": "Teste rápido para content_creator", + "output": "Erro de configuração: O modelo \"gemini-3-flash\" não está disponível. Verifique a configuração do modelo.", + "latencyMs": 3157, + "success": true, + "startedAt": "2025-12-20T19:36:37.686Z" + }, + { + "id": "9b1c9c88-b2a4-494b-9c26-0d18415e270f", + "spanType": "response", + "agentType": "goal_manager", + "output": "Erro de configuração: O modelo \"gemini-3-flash\" não está disponível. Verifique a configuração do modelo.", + "latencyMs": 1321, + "success": true, + "startedAt": "2025-12-20T19:36:26.469Z" + } + ] +} \ No newline at end of file diff --git a/backend/e2e-evidence/v4-2025-12-20/v4-metadata-response.json b/backend/e2e-evidence/v4-2025-12-20/v4-metadata-response.json new file mode 100644 index 000000000..a0f41ecda --- /dev/null +++ b/backend/e2e-evidence/v4-2025-12-20/v4-metadata-response.json @@ -0,0 +1,28 @@ +{ + "response": "Erro de configuração: O modelo \"gemini-3-flash\" não está disponível. Verifique a configuração do modelo.", + "conversationId": "773fb453-17c9-4556-a36c-e383d754a804", + "agentUsed": "general", + "mode": "auto", + "metadata": { + "processingTime": 12787, + "memoryFirstTime": 0, + "routingTime": 986, + "executionTime": 2706, + "routingConfidence": 0.5, + "routingReasoning": "Fallback para agente geral com ferramentas devido a erro ou ambiguidade", + "toolsAvailable": 9, + "toolsUsed": [], + "supermemoryMatches": 0, + "memoryFilterResult": { + "saved": false, + "type": "not_relevant", + "score": 0 + }, + "architecture": "v4-enhanced", + "traceId": "trace-1766259357735-2cef6vq1p", + "architectureVersion": "v4", + "agent": "general", + "googleAIConfigured": true, + "intelligentRouting": true + } +} \ No newline at end of file diff --git a/backend/e2e-evidence/v4-2025-12-20/v4-metrics-comparison.json b/backend/e2e-evidence/v4-2025-12-20/v4-metrics-comparison.json new file mode 100644 index 000000000..66ae29d34 --- /dev/null +++ b/backend/e2e-evidence/v4-2025-12-20/v4-metrics-comparison.json @@ -0,0 +1,109 @@ +{ + "timestamp": "2025-12-20T19:42:42.905Z", + "metrics": { + "agentInstantiation": [ + 50, + 50, + 50, + 50 + ], + "chatLatency": [ + 12873.75 + ], + "researchLatency": [], + "memoryRecall": 100, + "memorySearchResults": 9, + "successRate": 100, + "researchSuccessRate": 0, + "routingAccuracy": 100, + "workflowReuseRate": 0, + "avgTokensPerExecution": 26 + }, + "comparisons": [ + { + "metric": "Agent Instantiation", + "before": 200, + "after": 50, + "target": 10, + "improvement": 4, + "improvementPercent": 75, + "targetMet": false, + "category": "Performance" + }, + { + "metric": "Memory Recall", + "before": 70, + "after": 100, + "target": 85, + "improvement": 1.4285714285714286, + "improvementPercent": 30, + "targetMet": true, + "category": "Memory" + }, + { + "metric": "Overall Success Rate", + "before": 90, + "after": 100, + "target": 95, + "improvement": 1.1111111111111112, + "improvementPercent": 10, + "targetMet": true, + "category": "Reliability" + }, + { + "metric": "Routing Accuracy", + "before": 97, + "after": 100, + "target": 99, + "improvement": 1.0309278350515463, + "improvementPercent": 3, + "targetMet": true, + "category": "Reliability" + }, + { + "metric": "Avg Tokens per Execution", + "before": 2000, + "after": 26, + "target": 1500, + "improvement": 76.92307692307692, + "improvementPercent": 98.7, + "targetMet": true, + "category": "Cost" + }, + { + "metric": "Chat Latency (Balanced)", + "before": 4500, + "after": 12873.75, + "target": 2000, + "improvement": 0.34954849985435477, + "improvementPercent": -186.08333333333334, + "targetMet": false, + "category": "Performance" + } + ], + "summary": { + "targetsMet": "4/6 (66.7%)", + "baseline": { + "agentInstantiation": 200, + "chatLatency": 4500, + "researchLatency": 120000, + "memoryRecall": 70, + "successRate": 90, + "researchSuccessRate": 60, + "routingAccuracy": 97, + "workflowReuseRate": 0, + "avgTokensPerExecution": 2000 + }, + "target": { + "agentInstantiation": 10, + "chatLatency": 2000, + "researchLatency": 60000, + "memoryRecall": 85, + "successRate": 95, + "researchSuccessRate": 95, + "routingAccuracy": 99, + "workflowReuseRate": 40, + "avgTokensPerExecution": 1500 + } + } +} \ No newline at end of file diff --git a/backend/e2e-evidence/v4-2025-12-26/control-plane-stats.json b/backend/e2e-evidence/v4-2025-12-26/control-plane-stats.json new file mode 100644 index 000000000..cea5e77c3 --- /dev/null +++ b/backend/e2e-evidence/v4-2025-12-26/control-plane-stats.json @@ -0,0 +1,32 @@ +{ + "success": true, + "data": { + "v4Enabled": false, + "features": { + "agentFactory": true, + "tracing": true, + "memory": true, + "workflow": true, + "planning": true, + "reasoning": true, + "reflection": true, + "evaluation": true + }, + "stats": { + "agents": { + "cached": 1, + "maxCache": 50, + "hitRate": 0 + }, + "memory": { + "total": 0 + }, + "workflows": { + "cached": 4 + }, + "tracing": { + "spansLast7Days": 13 + } + } + } +} \ No newline at end of file diff --git a/backend/e2e-evidence/v4-2025-12-26/memory-search-results.json b/backend/e2e-evidence/v4-2025-12-26/memory-search-results.json new file mode 100644 index 000000000..d932d5369 --- /dev/null +++ b/backend/e2e-evidence/v4-2025-12-26/memory-search-results.json @@ -0,0 +1,120 @@ +{ + "memories": [ + { + "id": "8f65c730-b163-4582-a096-70596e3cc617", + "content": "Notei que usuários preferem respostas curtas", + "source_type": "conversation", + "metadata": { + "supermemory": { + "tags": [ + "general" + ], + "type": "general", + "savedAt": "2025-12-26T22:58:49.668Z", + "duration": "medium_term" + } + }, + "created_at": "2025-12-26T22:58:50.008Z" + }, + { + "id": "af23280f-d96e-49c2-96d3-d28cc7f5ebaa", + "content": "Acredito que Python é uma excelente linguagem para IA", + "source_type": "conversation", + "metadata": { + "supermemory": { + "tags": [ + "general" + ], + "type": "general", + "savedAt": "2025-12-26T22:58:48.188Z", + "duration": "medium_term" + } + }, + "created_at": "2025-12-26T22:58:48.528Z" + }, + { + "id": "29bbb3b5-ef1a-4fe6-98cf-030cb721e0ef", + "content": "Eu visitei o Rio de Janeiro em 2024", + "source_type": "conversation", + "metadata": { + "supermemory": { + "tags": [ + "general" + ], + "type": "general", + "savedAt": "2025-12-26T22:58:46.652Z", + "duration": "medium_term" + } + }, + "created_at": "2025-12-26T22:58:46.993Z" + }, + { + "id": "3054a4da-c0e7-4468-bae4-18347cda3003", + "content": "O Brasil é o maior país da América do Sul", + "source_type": "conversation", + "metadata": { + "supermemory": { + "tags": [ + "general" + ], + "type": "general", + "savedAt": "2025-12-26T22:58:45.013Z", + "duration": "medium_term" + } + }, + "created_at": "2025-12-26T22:58:45.354Z" + }, + { + "id": "1edc6efc-2351-48dd-817d-6ada0ab82e0f", + "content": "Teste rápido para research", + "source_type": "message", + "metadata": { + "type": "user_message", + "created_at": "2025-12-26T22:58:39.5749+00:00", + "auto_generated": true, + "conversation_id": "e6ef6f7b-5b50-4ada-b432-2b06b412ebd8", + "original_message_id": "61db552b-7c23-4b4b-8fe5-e7d4b18ef4ae" + }, + "created_at": "2025-12-26T22:58:39.574Z" + }, + { + "id": "953a765e-cda3-44a4-97e0-6dee4b46d6ae", + "content": "Teste rápido para content_creator", + "source_type": "message", + "metadata": { + "type": "user_message", + "created_at": "2025-12-26T22:58:18.22883+00:00", + "auto_generated": true, + "conversation_id": "e6ef6f7b-5b50-4ada-b432-2b06b412ebd8", + "original_message_id": "a99eac73-884e-48b8-ab64-52ac43678ba8" + }, + "created_at": "2025-12-26T22:58:18.228Z" + }, + { + "id": "6e3969c5-7691-408f-adca-80b207c5dbf9", + "content": "Teste rápido para goal_manager", + "source_type": "message", + "metadata": { + "type": "user_message", + "created_at": "2025-12-26T22:57:55.90025+00:00", + "auto_generated": true, + "conversation_id": "e6ef6f7b-5b50-4ada-b432-2b06b412ebd8", + "original_message_id": "74f36635-8ec3-4d73-94ef-e298a4c0c359" + }, + "created_at": "2025-12-26T22:57:55.900Z" + }, + { + "id": "9226d180-c003-472e-8018-e4b1364e8c12", + "content": "Teste rápido para task_manager", + "source_type": "message", + "metadata": { + "type": "user_message", + "created_at": "2025-12-26T22:57:33.37483+00:00", + "auto_generated": true, + "conversation_id": "e6ef6f7b-5b50-4ada-b432-2b06b412ebd8", + "original_message_id": "0ab0e28f-dd12-4341-b1e0-9db3976a30c3" + }, + "created_at": "2025-12-26T22:57:33.374Z" + } + ] +} \ No newline at end of file diff --git a/backend/e2e-evidence/v4-2025-12-26/tracing-spans.json b/backend/e2e-evidence/v4-2025-12-26/tracing-spans.json new file mode 100644 index 000000000..4b8c48b48 --- /dev/null +++ b/backend/e2e-evidence/v4-2025-12-26/tracing-spans.json @@ -0,0 +1,99 @@ +{ + "success": true, + "data": [ + { + "id": "3eb350b7-b09e-4aac-9da2-c851ff9bdff1", + "spanType": "router", + "agentType": null, + "input": "Teste de tracing V4", + "output": "Desculpe, não consegui processar sua mensagem neste momento. Por favor, tente reformulá-la ou fazer uma pergunta diferente.", + "latencyMs": 2297, + "success": true, + "startedAt": "2025-12-26T22:58:58.723Z" + }, + { + "id": "fe028e03-50db-4b10-a69c-0c657987db87", + "spanType": "response", + "agentType": "research", + "output": "Olá! Estou pronto para o teste do `research`. O que você gostaria de pesquisar ou fazer?\n\nCom as minhas ferramentas de pesquisa, posso te ajudar a:\n\n* **Realizar uma busca rápida na web:** \"Qual a c", + "latencyMs": 2736, + "success": true, + "startedAt": "2025-12-26T22:58:30.794Z" + }, + { + "id": "ec1f1004-7fdd-4923-b5a3-d32032afb170", + "spanType": "prompt", + "agentType": "research", + "input": "Teste rápido para research", + "latencyMs": 2203, + "success": true, + "startedAt": "2025-12-26T22:58:28.058Z" + }, + { + "id": "61954010-e17e-4bef-8a4d-60da37970f78", + "spanType": "router", + "agentType": null, + "input": "Teste rápido para research", + "output": "Olá! Estou pronto para o teste do `research`. O que você gostaria de pesquisar ou fazer?\n\nCom as minhas ferramentas de pesquisa, posso te ajudar a:\n\n* **Realizar uma busca rápida na web:** \"Qual a c", + "latencyMs": 3834, + "success": true, + "startedAt": "2025-12-26T22:58:27.495Z" + }, + { + "id": "76ab973b-890b-4fb6-a229-4b03bbee839b", + "spanType": "response", + "agentType": "content_creator", + "output": "Olá! Estou pronto para o teste do `content_creator`. O que você gostaria de criar ou fazer?\n\nCom as minhas ferramentas, posso te ajudar a:\n\n* **Criar um documento PDF:** \"Gere um PDF sobre os benefí", + "latencyMs": 3923, + "success": true, + "startedAt": "2025-12-26T22:58:09.407Z" + }, + { + "id": "e7e6fce4-baf2-4757-93ff-be117d7c1777", + "spanType": "prompt", + "agentType": "content_creator", + "input": "Teste rápido para content_creator", + "latencyMs": 3381, + "success": true, + "startedAt": "2025-12-26T22:58:05.484Z" + }, + { + "id": "b084562d-0a70-4f6a-a569-a4a4d8f20894", + "spanType": "router", + "agentType": null, + "input": "Teste rápido para content_creator", + "output": "Olá! Estou pronto para o teste do `content_creator`. O que você gostaria de criar ou fazer?\n\nCom as minhas ferramentas, posso te ajudar a:\n\n* **Criar um documento PDF:** \"Gere um PDF sobre os benefí", + "latencyMs": 4994, + "success": true, + "startedAt": "2025-12-26T22:58:04.947Z" + }, + { + "id": "a8ada4f0-4ad3-4d22-a603-79e061c55dc8", + "spanType": "response", + "agentType": "goal_manager", + "output": "Olá! Estou pronto para o teste do `goal_manager`. O que você gostaria de fazer?\n\nPosso te ajudar a:\n* **Criar uma nova meta:** \"Quero criar uma meta para aprender um novo idioma.\"\n* **Listar suas ", + "latencyMs": 3339, + "success": true, + "startedAt": "2025-12-26T22:57:46.683Z" + }, + { + "id": "71671b18-48e1-4985-9f70-b770f2b34176", + "spanType": "prompt", + "agentType": "goal_manager", + "input": "Teste rápido para goal_manager", + "latencyMs": 2802, + "success": true, + "startedAt": "2025-12-26T22:57:43.344Z" + }, + { + "id": "d086231a-45f7-49c0-8fa5-00b8b89e7a2f", + "spanType": "router", + "agentType": null, + "input": "Teste rápido para goal_manager", + "output": "Olá! Estou pronto para o teste do `goal_manager`. O que você gostaria de fazer?\n\nPosso te ajudar a:\n* **Criar uma nova meta:** \"Quero criar uma meta para aprender um novo idioma.\"\n* **Listar suas ", + "latencyMs": 4457, + "success": true, + "startedAt": "2025-12-26T22:57:42.760Z" + } + ] +} \ No newline at end of file diff --git a/backend/e2e-evidence/v4-2025-12-26/v4-metadata-response.json b/backend/e2e-evidence/v4-2025-12-26/v4-metadata-response.json new file mode 100644 index 000000000..e69de29bb diff --git a/backend/e2e-evidence/v4-2025-12-27/control-plane-stats.json b/backend/e2e-evidence/v4-2025-12-27/control-plane-stats.json new file mode 100644 index 000000000..990d5aba8 --- /dev/null +++ b/backend/e2e-evidence/v4-2025-12-27/control-plane-stats.json @@ -0,0 +1,32 @@ +{ + "success": true, + "data": { + "v4Enabled": false, + "features": { + "agentFactory": true, + "tracing": true, + "memory": true, + "workflow": true, + "planning": true, + "reasoning": true, + "reflection": true, + "evaluation": true + }, + "stats": { + "agents": { + "cached": 1, + "maxCache": 50, + "hitRate": 0.0625 + }, + "memory": { + "total": 1 + }, + "workflows": { + "cached": 4 + }, + "tracing": { + "spansLast7Days": 14 + } + } + } +} \ No newline at end of file diff --git a/backend/e2e-evidence/v4-2025-12-27/memory-search-results.json b/backend/e2e-evidence/v4-2025-12-27/memory-search-results.json new file mode 100644 index 000000000..7628b3d61 --- /dev/null +++ b/backend/e2e-evidence/v4-2025-12-27/memory-search-results.json @@ -0,0 +1,133 @@ +{ + "memories": [ + { + "id": "2875380b-aa61-42e1-b582-a376369e4ec0", + "content": "Notei que usuários preferem respostas curtas", + "source_type": "conversation", + "metadata": { + "supermemory": { + "tags": [ + "general" + ], + "type": "general", + "savedAt": "2025-12-27T02:43:35.393Z", + "duration": "medium_term" + } + }, + "created_at": "2025-12-27T02:43:35.732Z" + }, + { + "id": "8230dfda-f3be-4b32-b071-5b92fd7a26af", + "content": "Acredito que Python é uma excelente linguagem para IA", + "source_type": "conversation", + "metadata": { + "supermemory": { + "tags": [ + "general" + ], + "type": "general", + "savedAt": "2025-12-27T02:43:34.257Z", + "duration": "medium_term" + } + }, + "created_at": "2025-12-27T02:43:34.594Z" + }, + { + "id": "6c4773a6-fc62-4245-ace9-1e2ea3eb8670", + "content": "Eu visitei o Rio de Janeiro em 2024", + "source_type": "conversation", + "metadata": { + "supermemory": { + "tags": [ + "general" + ], + "type": "general", + "savedAt": "2025-12-27T02:43:33.135Z", + "duration": "medium_term" + } + }, + "created_at": "2025-12-27T02:43:33.473Z" + }, + { + "id": "51724f7b-51fb-4a01-a48c-142b6aaa0473", + "content": "O Brasil é o maior país da América do Sul", + "source_type": "conversation", + "metadata": { + "supermemory": { + "tags": [ + "general" + ], + "type": "general", + "savedAt": "2025-12-27T02:43:31.961Z", + "duration": "medium_term" + } + }, + "created_at": "2025-12-27T02:43:32.299Z" + }, + { + "id": "407bb571-2046-4ee0-92cd-2129b46d1bcf", + "content": "Teste rápido para research", + "source_type": "message", + "metadata": { + "type": "user_message", + "created_at": "2025-12-27T02:43:26.46232+00:00", + "auto_generated": true, + "conversation_id": "fb9535f7-2368-4c8c-93a9-456580d1ff88", + "original_message_id": "b8c3b02b-ee35-4bae-bf1f-408d9d0acd5f" + }, + "created_at": "2025-12-27T02:43:26.462Z" + }, + { + "id": "c0019508-0b3d-4b11-a528-5359da522bcb", + "content": "Teste rápido para content_creator", + "source_type": "message", + "metadata": { + "type": "user_message", + "created_at": "2025-12-27T02:43:03.556495+00:00", + "auto_generated": true, + "conversation_id": "fb9535f7-2368-4c8c-93a9-456580d1ff88", + "original_message_id": "48f0d033-6c52-4ef6-94f4-bb9100355cc0" + }, + "created_at": "2025-12-27T02:43:03.556Z" + }, + { + "id": "b2579923-a5ef-49cf-962b-d86ad2700517", + "content": "Teste rápido para goal_manager", + "source_type": "message", + "metadata": { + "type": "user_message", + "created_at": "2025-12-27T02:42:36.733965+00:00", + "auto_generated": true, + "conversation_id": "fb9535f7-2368-4c8c-93a9-456580d1ff88", + "original_message_id": "08662817-3331-448f-8fbd-e9439981eef0" + }, + "created_at": "2025-12-27T02:42:36.733Z" + }, + { + "id": "a1fc4e92-09ed-42f1-b6b9-f6b557e74123", + "content": "Teste rápido para task_manager", + "source_type": "message", + "metadata": { + "type": "user_message", + "created_at": "2025-12-27T02:42:14.210854+00:00", + "auto_generated": true, + "conversation_id": "fb9535f7-2368-4c8c-93a9-456580d1ff88", + "original_message_id": "c9875936-e800-4acb-8b8b-ba0fbfddf2f0" + }, + "created_at": "2025-12-27T02:42:14.210Z" + }, + { + "id": "42ab0e1f-96bf-49d0-8481-ec93637ea5fa", + "content": "Olá, estou testando a V4. Responda brevemente.", + "source_type": "message", + "metadata": { + "type": "user_message", + "created_at": "2025-12-27T02:41:56.064771+00:00", + "auto_generated": true, + "conversation_id": "fb9535f7-2368-4c8c-93a9-456580d1ff88", + "original_message_id": "87c22c93-ad62-42a4-bf8f-48c1566532a6" + }, + "created_at": "2025-12-27T02:41:56.064Z" + } + ] +} \ No newline at end of file diff --git a/backend/e2e-evidence/v4-2025-12-27/research-agent-response.json b/backend/e2e-evidence/v4-2025-12-27/research-agent-response.json new file mode 100644 index 000000000..9e6aada5e --- /dev/null +++ b/backend/e2e-evidence/v4-2025-12-27/research-agent-response.json @@ -0,0 +1,29 @@ +{ + "agentUsed": "research", + "responseLength": 920, + "latency": 34714, + "metadata": { + "processingTime": 33524, + "memoryFirstTime": 0, + "routingTime": 0, + "executionTime": 17652, + "routingConfidence": 1, + "routingReasoning": "Agente forçado pela requisição", + "toolsAvailable": 8, + "toolsUsed": [ + "web_search" + ], + "supermemoryMatches": 0, + "memoryFilterResult": { + "saved": false, + "type": "not_relevant", + "score": 0.1 + }, + "architecture": "v4-enhanced", + "traceId": "trace-1766803458786-hzvxt3ss6", + "architectureVersion": "v4", + "agent": "research", + "googleAIConfigured": true, + "intelligentRouting": true + } +} \ No newline at end of file diff --git a/backend/e2e-evidence/v4-2025-12-27/tracing-spans.json b/backend/e2e-evidence/v4-2025-12-27/tracing-spans.json new file mode 100644 index 000000000..6aad095ae --- /dev/null +++ b/backend/e2e-evidence/v4-2025-12-27/tracing-spans.json @@ -0,0 +1,99 @@ +{ + "success": true, + "data": [ + { + "id": "0c3a7a8c-a6c8-4c47-80e2-eef3ea721864", + "spanType": "router", + "agentType": null, + "input": "Teste de tracing V4", + "output": "Desculpe, não consegui processar sua mensagem neste momento. Por favor, tente reformulá-la ou fazer uma pergunta diferente.", + "latencyMs": 3682, + "success": true, + "startedAt": "2025-12-27T02:43:44.379Z" + }, + { + "id": "2467d372-d50b-4e77-b49f-d9110b586720", + "spanType": "response", + "agentType": "research", + "output": "Olá! Para um teste rápido, posso realizar uma pesquisa web autônoma. Qual seria o tópico da pesquisa?", + "latencyMs": 3194, + "success": true, + "startedAt": "2025-12-27T02:43:16.426Z" + }, + { + "id": "740c24ea-41cc-4226-a12f-a7d41a5a6c7c", + "spanType": "prompt", + "agentType": "research", + "input": "Teste rápido para research", + "latencyMs": 2334, + "success": true, + "startedAt": "2025-12-27T02:43:13.232Z" + }, + { + "id": "dbb1c8f3-1fc0-4624-97a9-40fb40de1520", + "spanType": "router", + "agentType": null, + "input": "Teste rápido para research", + "output": "Olá! Para um teste rápido, posso realizar uma pesquisa web autônoma. Qual seria o tópico da pesquisa?", + "latencyMs": 4252, + "success": true, + "startedAt": "2025-12-27T02:43:12.701Z" + }, + { + "id": "c2898383-a103-40b2-a65d-b1b0f27fe7df", + "spanType": "response", + "agentType": "content_creator", + "output": "Olá! Para um teste rápido, posso gerar uma imagem para você. Qual seria a descrição da imagem que você gostaria de criar?", + "latencyMs": 2753, + "success": true, + "startedAt": "2025-12-27T02:42:50.688Z" + }, + { + "id": "f0b63ad9-9ca8-41fe-a8e1-495803069252", + "spanType": "prompt", + "agentType": "content_creator", + "input": "Teste rápido para content_creator", + "latencyMs": 2205, + "success": true, + "startedAt": "2025-12-27T02:42:47.935Z" + }, + { + "id": "17f665e5-287d-47ee-8fd3-526ad72c1f43", + "spanType": "router", + "agentType": null, + "input": "Teste rápido para content_creator", + "output": "Olá! Para um teste rápido, posso gerar uma imagem para você. Qual seria a descrição da imagem que você gostaria de criar?", + "latencyMs": 3809, + "success": true, + "startedAt": "2025-12-27T02:42:47.409Z" + }, + { + "id": "9450c6b4-ae38-4cff-b7a3-94b949ba01f7", + "spanType": "response", + "agentType": "goal_manager", + "output": "Olá! Para um teste rápido, posso criar uma meta para você. Qual seria o título da meta e qual é o seu ID de usuário?", + "latencyMs": 2165, + "success": true, + "startedAt": "2025-12-27T02:42:26.643Z" + }, + { + "id": "e071d5dd-ba0e-4858-a88b-609f46fb8cee", + "spanType": "prompt", + "agentType": "goal_manager", + "input": "Teste rápido para goal_manager", + "latencyMs": 1637, + "success": true, + "startedAt": "2025-12-27T02:42:24.478Z" + }, + { + "id": "ee15ec16-3d00-49cb-b563-6d75925ec1d3", + "spanType": "router", + "agentType": null, + "input": "Teste rápido para goal_manager", + "output": "Olá! Para um teste rápido, posso criar uma meta para você. Qual seria o título da meta e qual é o seu ID de usuário?", + "latencyMs": 3226, + "success": true, + "startedAt": "2025-12-27T02:42:23.951Z" + } + ] +} \ No newline at end of file diff --git a/backend/e2e-evidence/v4-2025-12-27/v4-metadata-response.json b/backend/e2e-evidence/v4-2025-12-27/v4-metadata-response.json new file mode 100644 index 000000000..ed0277597 --- /dev/null +++ b/backend/e2e-evidence/v4-2025-12-27/v4-metadata-response.json @@ -0,0 +1,28 @@ +{ + "response": "Desculpe, não consegui processar sua mensagem neste momento. Por favor, tente reformulá-la ou fazer uma pergunta diferente.", + "conversationId": "fb9535f7-2368-4c8c-93a9-456580d1ff88", + "agentUsed": "conversational", + "mode": "auto", + "metadata": { + "processingTime": 23097, + "memoryFirstTime": 0, + "routingTime": 1445, + "executionTime": 189, + "routingConfidence": 0.95, + "routingReasoning": "A mensagem é uma saudação e uma declaração de teste, sem solicitar uma ação específica que exija uma ferramenta especializada. É uma interação casual.", + "toolsAvailable": 2, + "toolsUsed": [], + "supermemoryMatches": 0, + "memoryFilterResult": { + "saved": true, + "type": "preference", + "score": 0.6 + }, + "architecture": "v4-enhanced", + "traceId": "trace-1766803299458-fomae67p5", + "architectureVersion": "v4", + "agent": "conversational", + "googleAIConfigured": true, + "intelligentRouting": true + } +} \ No newline at end of file diff --git a/backend/e2e-evidence/v4-2025-12-27/v4-metrics-comparison.json b/backend/e2e-evidence/v4-2025-12-27/v4-metrics-comparison.json new file mode 100644 index 000000000..20d9d3f21 --- /dev/null +++ b/backend/e2e-evidence/v4-2025-12-27/v4-metrics-comparison.json @@ -0,0 +1,109 @@ +{ + "timestamp": "2025-12-27T02:50:20.152Z", + "metrics": { + "agentInstantiation": [ + 50, + 50, + 50, + 50 + ], + "chatLatency": [ + 23102.5 + ], + "researchLatency": [], + "memoryRecall": 100, + "memorySearchResults": 9, + "successRate": 100, + "researchSuccessRate": 0, + "routingAccuracy": 100, + "workflowReuseRate": 0, + "avgTokensPerExecution": 28.625 + }, + "comparisons": [ + { + "metric": "Agent Instantiation", + "before": 200, + "after": 50, + "target": 10, + "improvement": 4, + "improvementPercent": 75, + "targetMet": false, + "category": "Performance" + }, + { + "metric": "Memory Recall", + "before": 70, + "after": 100, + "target": 85, + "improvement": 1.4285714285714286, + "improvementPercent": 30, + "targetMet": true, + "category": "Memory" + }, + { + "metric": "Overall Success Rate", + "before": 90, + "after": 100, + "target": 95, + "improvement": 1.1111111111111112, + "improvementPercent": 10, + "targetMet": true, + "category": "Reliability" + }, + { + "metric": "Routing Accuracy", + "before": 97, + "after": 100, + "target": 99, + "improvement": 1.0309278350515463, + "improvementPercent": 3, + "targetMet": true, + "category": "Reliability" + }, + { + "metric": "Avg Tokens per Execution", + "before": 2000, + "after": 28.625, + "target": 1500, + "improvement": 69.86899563318778, + "improvementPercent": 98.56875000000001, + "targetMet": true, + "category": "Cost" + }, + { + "metric": "Chat Latency (Balanced)", + "before": 4500, + "after": 23102.5, + "target": 2000, + "improvement": 0.19478411427334705, + "improvementPercent": -413.38888888888886, + "targetMet": false, + "category": "Performance" + } + ], + "summary": { + "targetsMet": "4/6 (66.7%)", + "baseline": { + "agentInstantiation": 200, + "chatLatency": 4500, + "researchLatency": 120000, + "memoryRecall": 70, + "successRate": 90, + "researchSuccessRate": 60, + "routingAccuracy": 97, + "workflowReuseRate": 0, + "avgTokensPerExecution": 2000 + }, + "target": { + "agentInstantiation": 10, + "chatLatency": 2000, + "researchLatency": 60000, + "memoryRecall": 85, + "successRate": 95, + "researchSuccessRate": 95, + "routingAccuracy": 99, + "workflowReuseRate": 40, + "avgTokensPerExecution": 1500 + } + } +} \ No newline at end of file diff --git a/backend/package-lock.json b/backend/package-lock.json index 3e35a9129..1466393df 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1866,16 +1866,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@borewit/text-codec": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.1.tgz", - "integrity": "sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/@bufbuild/protobuf": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.11.0.tgz", diff --git a/backend/src/routes/intelligent-agents.ts.backup b/backend/src/routes/intelligent-agents.ts.backup new file mode 100644 index 000000000..c37ba896b --- /dev/null +++ b/backend/src/routes/intelligent-agents.ts.backup @@ -0,0 +1,558 @@ +/** + * Rotas para os agentes inteligentes: + * - Goal Manager + * - Task Enricher + * - Automation Manager + * - Memory Manager + * - 🆕 Intelligent Master Agent (com inteligência conversacional) + */ + +import { Router, Response } from 'express'; +import { authenticateToken, AuthRequest } from '../middleware/auth'; +import { asyncHandler, ValidationError } from '../middleware/errorHandler'; +import { goalManagerAgent } from '../services/langchain/agents/goal-manager-agent'; +import { taskEnricherAgent } from '../services/langchain/agents/task-enricher-agent'; +import { automationManagerAgent } from '../services/langchain/agents/automation-manager-agent'; +import { memoryManagerAgent } from '../services/langchain/agents/memory-manager-agent'; +import { intelligentMasterAgent } from '../services/langchain/intelligent-master-agent'; + +const router = Router(); + +// ============================================ +// 🆕 INTELLIGENT MASTER AGENT (Conversacional) +// ============================================ + +/** + * POST /api/intelligent-agents/process + * Processar mensagem com inteligência conversacional + * + * Este endpoint usa o sistema de inteligência conversacional que: + * - Condensa perguntas (máx 2-3) + * - Traz sugestões proativas + * - Conversa naturalmente + * - Detecta tipo automaticamente + */ +router.post('/process', authenticateToken, asyncHandler(async (req: AuthRequest, res: Response) => { + const userId = req.user?.id; + if (!userId) { + throw new ValidationError('User ID not found'); + } + + const { content, conversationHistory } = req.body; + + if (!content) { + throw new ValidationError('Content is required'); + } + + const response = await intelligentMasterAgent.processMessage( + { content, userId }, + { conversationHistory } + ); + + res.json({ + success: true, + ...response, + }); +})); + +/** + * POST /api/intelligent-agents/chat + * Chat conversacional (compatível com formato de mensagens) + * + * Aceita formato { messages: [...] } e processa com inteligência conversacional + */ +router.post('/chat', authenticateToken, asyncHandler(async (req: AuthRequest, res: Response) => { + const userId = req.user?.id; + if (!userId) { + throw new ValidationError('User ID not found'); + } + + const { messages } = req.body; + + if (!messages || !Array.isArray(messages) || messages.length === 0) { + throw new ValidationError('Messages array is required'); + } + + // Extrair última mensagem do usuário + const lastMessage = messages[messages.length - 1]; + + // Extrair histórico (últimas 5 mensagens, excluindo a atual) + const conversationHistory = messages.slice(-6, -1).map((msg: any) => ({ + role: msg.role, + content: msg.content, + })); + + const response = await intelligentMasterAgent.processMessage( + { content: lastMessage.content, userId }, + { conversationHistory } + ); + + res.json({ + success: true, + response: response.response, + action: response.action, + data: response.data, + suggestions: response.suggestions, + conversationalMode: response.conversationalMode, + requiresFollowUp: response.requiresFollowUp, + followUpQuestions: response.followUpQuestions, + }); +})); + +/** + * POST /api/intelligent-agents/condense-questions + * Condensar múltiplas perguntas em 2-3 essenciais + */ +router.post('/condense-questions', authMiddleware, async (req: Request, res: Response) => { + try { + const { questions } = req.body; + + if (!questions || !Array.isArray(questions)) { + return res.status(400).json({ error: 'Questions array is required' }); + } + + const { conversationalIntelligence } = await import('../services/langchain/conversational-intelligence'); + const condensed = await conversationalIntelligence.condenseQuestions(questions); + + res.json({ + success: true, + original: questions, + condensed, + reduction: `${questions.length} → ${condensed.length}`, + }); + } catch (error: any) { + console.error('[IntelligentMaster] Error condensing questions:', error); + res.status(500).json({ + success: false, + error: error.message + }); + } +}); + +// ============================================ +// GOAL MANAGER ROUTES +// ============================================ + +/** + * POST /api/intelligent-agents/goals/create + * Criar um novo objetivo com enriquecimento inteligente + */ +router.post('/goals/create', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { title, description, goalType, targetDate, metrics } = req.body; + + if (!title) { + return res.status(400).json({ error: 'Title is required' }); + } + + const result = await goalManagerAgent.createGoal(userId, { + title, + description, + goalType, + targetDate: targetDate ? new Date(targetDate) : undefined, + metrics, + }); + + res.json(result); + } catch (error: any) { + console.error('[Goals] Error creating goal:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * POST /api/intelligent-agents/goals/:goalId/generate-plan + * Gerar plano completo para um objetivo + */ +router.post('/goals/:goalId/generate-plan', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { goalId } = req.params; + const { userAnswers } = req.body; + + const result = await goalManagerAgent.generatePlan(userId, { + goalId, + userAnswers, + }); + + res.json(result); + } catch (error: any) { + console.error('[Goals] Error generating plan:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * GET /api/intelligent-agents/goals/:goalId/progress + * Atualizar e obter progresso de um objetivo + */ +router.get('/goals/:goalId/progress', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { goalId } = req.params; + + const result = await goalManagerAgent.updateProgress(userId, goalId); + res.json(result); + } catch (error: any) { + console.error('[Goals] Error updating progress:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * GET /api/intelligent-agents/goals + * Listar objetivos do usuário + */ +router.get('/goals', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { status, goalType } = req.query; + + const goals = await goalManagerAgent.listGoals(userId, { + status: status as string, + goalType: goalType as string, + }); + + res.json({ goals }); + } catch (error: any) { + console.error('[Goals] Error listing goals:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * POST /api/intelligent-agents/goals/:goalId/suggest-actions + * Sugerir ações para um objetivo + */ +router.post('/goals/:goalId/suggest-actions', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { goalId } = req.params; + + const result = await goalManagerAgent.suggestActions(userId, goalId); + res.json(result); + } catch (error: any) { + console.error('[Goals] Error suggesting actions:', error); + res.status(500).json({ error: error.message }); + } +}); + +// ============================================ +// TASK ENRICHER ROUTES +// ============================================ + +/** + * POST /api/intelligent-agents/tasks/create + * Criar uma nova tarefa com enriquecimento inteligente + */ +router.post('/tasks/create', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { title, description, dueDate, priority, goalId } = req.body; + + if (!title) { + return res.status(400).json({ error: 'Title is required' }); + } + + const result = await taskEnricherAgent.createTask(userId, { + title, + description, + dueDate: dueDate ? new Date(dueDate) : undefined, + priority, + goalId, + }); + + res.json(result); + } catch (error: any) { + console.error('[Tasks] Error creating task:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * POST /api/intelligent-agents/tasks/:taskId/enrich + * Enriquecer uma tarefa existente + */ +router.post('/tasks/:taskId/enrich', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { taskId } = req.params; + const { userAnswers } = req.body; + + const result = await taskEnricherAgent.enrichExistingTask(userId, taskId, userAnswers); + res.json(result); + } catch (error: any) { + console.error('[Tasks] Error enriching task:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * GET /api/intelligent-agents/tasks/:taskId/next-steps + * Sugerir próximos passos para uma tarefa + */ +router.get('/tasks/:taskId/next-steps', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { taskId } = req.params; + + const result = await taskEnricherAgent.suggestNextSteps(userId, taskId); + res.json(result); + } catch (error: any) { + console.error('[Tasks] Error suggesting next steps:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * POST /api/intelligent-agents/tasks/:taskId/checklist + * Gerar checklist para uma tarefa + */ +router.post('/tasks/:taskId/checklist', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { taskId } = req.params; + + const result = await taskEnricherAgent.generateChecklist(userId, taskId); + res.json(result); + } catch (error: any) { + console.error('[Tasks] Error generating checklist:', error); + res.status(500).json({ error: error.message }); + } +}); + +// ============================================ +// AUTOMATION MANAGER ROUTES +// ============================================ + +/** + * POST /api/intelligent-agents/automations/create + * Criar uma nova automação + */ +router.post('/automations/create', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { title, description, automationType, schedule, config, integrationType, integrationConfig } = req.body; + + if (!title || !automationType || !schedule) { + return res.status(400).json({ error: 'Title, automationType and schedule are required' }); + } + + const result = await automationManagerAgent.createAutomation(userId, { + title, + description, + automationType, + schedule, + config, + integrationType, + integrationConfig, + }); + + res.json(result); + } catch (error: any) { + console.error('[Automations] Error creating automation:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * POST /api/intelligent-agents/automations/:automationId/execute + * Executar uma automação manualmente + */ +router.post('/automations/:automationId/execute', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { automationId } = req.params; + + const result = await automationManagerAgent.executeAutomation(automationId, userId); + res.json(result); + } catch (error: any) { + console.error('[Automations] Error executing automation:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * GET /api/intelligent-agents/automations + * Listar automações do usuário + */ +router.get('/automations', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { status, type } = req.query; + + const automations = await automationManagerAgent.listAutomations(userId, { + status: status as string, + type: type as string, + }); + + res.json({ automations }); + } catch (error: any) { + console.error('[Automations] Error listing automations:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * POST /api/intelligent-agents/automations/:automationId/pause + * Pausar uma automação + */ +router.post('/automations/:automationId/pause', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { automationId } = req.params; + + const result = await automationManagerAgent.pauseAutomation(automationId, userId); + res.json(result); + } catch (error: any) { + console.error('[Automations] Error pausing automation:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * POST /api/intelligent-agents/automations/:automationId/resume + * Retomar uma automação + */ +router.post('/automations/:automationId/resume', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { automationId } = req.params; + + const result = await automationManagerAgent.resumeAutomation(automationId, userId); + res.json(result); + } catch (error: any) { + console.error('[Automations] Error resuming automation:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * DELETE /api/intelligent-agents/automations/:automationId + * Cancelar uma automação + */ +router.delete('/automations/:automationId', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { automationId } = req.params; + + const result = await automationManagerAgent.cancelAutomation(automationId, userId); + res.json(result); + } catch (error: any) { + console.error('[Automations] Error cancelling automation:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * GET /api/intelligent-agents/automations/:automationId/history + * Obter histórico de execuções + */ +router.get('/automations/:automationId/history', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { automationId } = req.params; + const limit = parseInt(req.query.limit as string) || 10; + + const history = await automationManagerAgent.getExecutionHistory(automationId, userId, limit); + res.json({ history }); + } catch (error: any) { + console.error('[Automations] Error getting history:', error); + res.status(500).json({ error: error.message }); + } +}); + +// ============================================ +// MEMORY MANAGER ROUTES +// ============================================ + +/** + * POST /api/intelligent-agents/memory/save + * Salvar informação na memória ou vault + */ +router.post('/memory/save', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { content, isPassword } = req.body; + + if (!content) { + return res.status(400).json({ error: 'Content is required' }); + } + + const result = await memoryManagerAgent.saveMemory(userId, { + content, + isPassword, + }); + + res.json(result); + } catch (error: any) { + console.error('[Memory] Error saving memory:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * POST /api/intelligent-agents/memory/search + * Buscar informação na memória + */ +router.post('/memory/search', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { query, limit } = req.body; + + if (!query) { + return res.status(400).json({ error: 'Query is required' }); + } + + const result = await memoryManagerAgent.searchMemory(userId, { + query, + limit, + }); + + res.json(result); + } catch (error: any) { + console.error('[Memory] Error searching memory:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * POST /api/intelligent-agents/vault/retrieve + * Recuperar senha do vault + */ +router.post('/vault/retrieve', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + const { query } = req.body; + + if (!query) { + return res.status(400).json({ error: 'Query is required' }); + } + + const result = await memoryManagerAgent.retrieveFromVault(userId, query); + res.json(result); + } catch (error: any) { + console.error('[Vault] Error retrieving from vault:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * GET /api/intelligent-agents/vault/list + * Listar entradas do vault (sem senhas) + */ +router.get('/vault/list', authMiddleware, async (req: Request, res: Response) => { + try { + const userId = (req as any).user.id; + + const entries = await memoryManagerAgent.listVaultEntries(userId); + res.json({ entries }); + } catch (error: any) { + console.error('[Vault] Error listing vault entries:', error); + res.status(500).json({ error: error.message }); + } +}); + +export default router; + diff --git a/docs/FRONTEND_SIDEBAR_AUDIT.md b/docs/FRONTEND_SIDEBAR_AUDIT.md new file mode 100644 index 000000000..94924696e --- /dev/null +++ b/docs/FRONTEND_SIDEBAR_AUDIT.md @@ -0,0 +1,115 @@ +# Frontend Sidebar Audit – Side menu stops working after entering app/chat + +**Date:** January 2026 +**Issue:** Sidebar navigation links stop working when user enters the app (specifically on the chat/Dashboard page). + +--- + +## 1. Summary of findings + +### 1.1 What was checked + +- **Layout:** AppLayout uses flex row: sidebar (`