From dc6b8b24bc06678cec9c8f5502db867ca4547891 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Thu, 12 Sep 2024 13:14:23 +0200 Subject: [PATCH 01/14] feat(copilot): implement the /docs command VSCODE-570 --- package-lock.json | 794 ++++++++++++++++++++++-- package.json | 6 + src/participant/docsChatbotAIService.ts | 154 +++++ src/participant/participant.ts | 73 ++- 4 files changed, 960 insertions(+), 67 deletions(-) create mode 100644 src/participant/docsChatbotAIService.ts diff --git a/package-lock.json b/package-lock.json index f40460af4..b007703ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "mongodb-data-service": "^22.23.0", "mongodb-log-writer": "^1.4.2", "mongodb-query-parser": "^4.2.2", + "mongodb-rag-core": "^0.4.1", "mongodb-schema": "^12.2.0", "numeral": "^2.0.6", "react": "^18.3.1", @@ -146,6 +147,28 @@ "node": ">=6.0.0" } }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.25.2.tgz", + "integrity": "sha512-F1Hck/asswwidFLtGdMg3XYgRxEUfygNbpkq5KEaEGsHNaSfxeX18/uZGQCL0oQNcj/tYNx8BaFXVwRhFDi45g==", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + } + }, + "node_modules/@anthropic-ai/sdk/node_modules/@types/node": { + "version": "18.19.50", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.50.tgz", + "integrity": "sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/@asamuzakjp/dom-selector": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-2.0.2.tgz", @@ -857,6 +880,33 @@ } } }, + "node_modules/@azure-rest/core-client": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure-rest/core-client/-/core-client-1.4.0.tgz", + "integrity": "sha512-ozTDPBVUDR5eOnMIwhggbnVmOrka4fXCs8n8mvUo4WLLc38kki6bAOByDoVZZPz/pZy2jMt2kwfpvy/UjALj6w==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-rest-pipeline": "^1.5.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure-rest/core-client/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@azure/abort-controller": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", @@ -873,7 +923,6 @@ "version": "1.7.2", "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz", "integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==", - "dev": true, "dependencies": { "@azure/abort-controller": "^2.0.0", "@azure/core-util": "^1.1.0", @@ -887,7 +936,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", - "dev": true, "dependencies": { "tslib": "^2.6.2" }, @@ -929,7 +977,6 @@ "version": "1.16.1", "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.1.tgz", "integrity": "sha512-ExPSbgjwCoht6kB7B4MeZoBAxcQSIl29r/bPeazZJx50ej4JJCByimLOrZoIsurISNyJQQHf30b3JfqC3Hb88A==", - "dev": true, "dependencies": { "@azure/abort-controller": "^2.0.0", "@azure/core-auth": "^1.4.0", @@ -948,7 +995,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", - "dev": true, "dependencies": { "tslib": "^2.6.2" }, @@ -960,7 +1006,6 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", - "dev": true, "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -969,11 +1014,21 @@ "node": ">= 14" } }, + "node_modules/@azure/core-sse": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@azure/core-sse/-/core-sse-2.1.3.tgz", + "integrity": "sha512-KSSdIKy8kvWCpYr8Hzpu22j3wcXsVTYE0IlgmI1T/aHvBDsLgV91y90UTfVWnuiuApRLCCVC4gS09ApBGOmYQA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@azure/core-tracing": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.1.2.tgz", "integrity": "sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA==", - "dev": true, "dependencies": { "tslib": "^2.6.2" }, @@ -985,7 +1040,6 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.9.0.tgz", "integrity": "sha512-AfalUQ1ZppaKuxPPMsFEUdX6GZPB3d9paR9d/TTL7Ow2De8cJaC7ibi7kWVlFAVPCYo31OcnGymc0R89DX8Oaw==", - "dev": true, "dependencies": { "@azure/abort-controller": "^2.0.0", "tslib": "^2.6.2" @@ -998,7 +1052,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", - "dev": true, "dependencies": { "tslib": "^2.6.2" }, @@ -1061,7 +1114,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.2.tgz", "integrity": "sha512-l170uE7bsKpIU6B/giRc9i4NI0Mj+tANMMMxf7Zi/5cKzEqPayP7+X1WPrG7e+91JgY8N+7K7nF2WOi7iVhXvg==", - "dev": true, "dependencies": { "tslib": "^2.6.2" }, @@ -1104,6 +1156,23 @@ "node": ">=16" } }, + "node_modules/@azure/openai": { + "version": "1.0.0-beta.12", + "resolved": "https://registry.npmjs.org/@azure/openai/-/openai-1.0.0-beta.12.tgz", + "integrity": "sha512-qKblxr6oVa8GsyNzY+/Ub9VmEsPYKhBrUrPaNEQiM+qrxnBPVm9kaeqGFFb/U78Q2zOabmhF9ctYt3xBW0nWnQ==", + "dependencies": { + "@azure-rest/core-client": "^1.1.7", + "@azure/core-auth": "^1.4.0", + "@azure/core-rest-pipeline": "^1.13.0", + "@azure/core-sse": "^2.0.0", + "@azure/core-util": "^1.4.0", + "@azure/logger": "^1.0.3", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", @@ -1757,6 +1826,14 @@ "w3c-keyname": "^2.2.4" } }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -1779,6 +1856,16 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -2280,6 +2367,122 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@langchain/anthropic": { + "version": "0.2.18", + "resolved": "https://registry.npmjs.org/@langchain/anthropic/-/anthropic-0.2.18.tgz", + "integrity": "sha512-4ZDTxMwGKTPRAi2Supu/faBSmwPIm/ga5QlazyO78Mf/8QbDR2DcvM5394FAy+X/nRAfnMbyXteO5IRJm653gw==", + "dependencies": { + "@anthropic-ai/sdk": "^0.25.2", + "@langchain/core": ">=0.2.21 <0.3.0", + "fast-xml-parser": "^4.4.1", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@langchain/core": { + "version": "0.2.32", + "resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.2.32.tgz", + "integrity": "sha512-S27M+9Qou2qtcLfFGEvANkJ/zHq5XApeQsR6Q4I7C6v9x07eoYr558h6vVy6WQmKcksgbCIJ854ikwp173wBjA==", + "dependencies": { + "ansi-styles": "^5.0.0", + "camelcase": "6", + "decamelize": "1.2.0", + "js-tiktoken": "^1.0.12", + "langsmith": "^0.1.43", + "mustache": "^4.2.0", + "p-queue": "^6.6.2", + "p-retry": "4", + "uuid": "^10.0.0", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@langchain/core/node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==" + }, + "node_modules/@langchain/core/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@langchain/core/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@langchain/core/node_modules/langsmith": { + "version": "0.1.55", + "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.1.55.tgz", + "integrity": "sha512-6NVtI04UUnIY59I/imOX02FG/QMGfqStu8tiJtyyreKMv2GAN0EE9Z5Ap1wzOe6v8ukEcV3NwEO2LYOPwup1PQ==", + "dependencies": { + "@types/uuid": "^10.0.0", + "commander": "^10.0.1", + "p-queue": "^6.6.2", + "p-retry": "4", + "semver": "^7.6.3", + "uuid": "^10.0.0" + }, + "peerDependencies": { + "@langchain/core": "*", + "langchain": "*", + "openai": "*" + }, + "peerDependenciesMeta": { + "@langchain/core": { + "optional": true + }, + "langchain": { + "optional": true + }, + "openai": { + "optional": true + } + } + }, + "node_modules/@langchain/core/node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@langchain/openai": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-0.2.10.tgz", + "integrity": "sha512-ph5sYDAmhP55Fs3TW3+LXiqF+r/5zaaNO2tur9p2Otr8KWNDSgp5ezfPki1WWfuUJVoSQ+6HDYtr6n2V5N1Lew==", + "dependencies": { + "@langchain/core": ">=0.2.26 <0.3.0", + "js-tiktoken": "^1.0.12", + "openai": "^4.57.3", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.3" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@leafygreen-ui/a11y": { "version": "1.4.13", "resolved": "https://registry.npmjs.org/@leafygreen-ui/a11y/-/a11y-1.4.13.tgz", @@ -5802,7 +6005,6 @@ "version": "2.6.11", "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", - "dev": true, "dependencies": { "@types/node": "*", "form-data": "^4.0.0" @@ -5821,8 +6023,7 @@ "node_modules/@types/qs": { "version": "6.9.15", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", - "dev": true + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==" }, "node_modules/@types/react": { "version": "17.0.80", @@ -5874,6 +6075,11 @@ "@types/node": "*" } }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, "node_modules/@types/scheduler": { "version": "0.16.3", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", @@ -5928,6 +6134,11 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "node_modules/@types/use-sync-external-store": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", @@ -6833,7 +7044,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dev": true, "dependencies": { "event-target-shim": "^5.0.0" }, @@ -6898,7 +7108,6 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", - "dev": true, "dependencies": { "humanize-ms": "^1.2.1" }, @@ -7204,11 +7413,15 @@ "node": ">=4" } }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/available-typed-arrays": { "version": "1.0.5", @@ -7226,6 +7439,16 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" }, + "node_modules/axios": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/azure-devops-node-api": { "version": "12.5.0", "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", @@ -7879,6 +8102,17 @@ "node": ">=6" } }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001651", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", @@ -8186,6 +8420,15 @@ "node": ">=16" } }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -8202,6 +8445,28 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", @@ -8217,11 +8482,19 @@ "node": ">=0.1.90" } }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -8233,11 +8506,18 @@ "version": "10.0.1", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "dev": true, "engines": { "node": ">=14" } }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/compare-module-exports": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/compare-module-exports/-/compare-module-exports-2.1.0.tgz", @@ -9117,7 +9397,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -9173,18 +9452,6 @@ "balanced-match": "^1.0.0" } }, - "node_modules/depcheck/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/depcheck/node_modules/minimatch": { "version": "7.4.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", @@ -9689,6 +9956,11 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "devOptional": true }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -10830,7 +11102,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "dev": true, "engines": { "node": ">=6" } @@ -10880,6 +11151,11 @@ "node": ">=0.10.0" } }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==" + }, "node_modules/express": { "version": "4.19.2", "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", @@ -10934,6 +11210,17 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -11079,6 +11366,11 @@ "pend": "~1.2.0" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "node_modules/fetch-blob": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", @@ -11252,6 +11544,11 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "node_modules/focus-trap": { "version": "6.9.4", "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.9.4.tgz", @@ -11274,6 +11571,25 @@ "react-dom": ">=16.3.0" } }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -11421,7 +11737,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -11434,14 +11749,12 @@ "node_modules/form-data-encoder": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", - "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", - "dev": true + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" }, "node_modules/formdata-node": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", - "dev": true, "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "4.0.0-beta.3" @@ -11454,7 +11767,6 @@ "version": "4.0.0-beta.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", - "dev": true, "engines": { "node": ">= 14" } @@ -11487,6 +11799,14 @@ "node": ">= 0.6" } }, + "node_modules/front-matter": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", + "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", + "dependencies": { + "js-yaml": "^3.13.1" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -11929,6 +12249,20 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, "node_modules/gzip-size": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", @@ -12392,7 +12726,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, "dependencies": { "ms": "^2.0.0" } @@ -12930,6 +13263,14 @@ "resolved": "https://registry.npmjs.org/is-electron-renderer/-/is-electron-renderer-2.0.1.tgz", "integrity": "sha512-pRlQnpaCFhDVPtkXkP+g9Ybv/CjbiQDjnKFQTEjpBfDKeV6dRDBczuFRDpM6DVfk2EjpMS8t5kwE5jPnqYl3zA==" }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -13308,6 +13649,14 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/js-tiktoken": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.14.tgz", + "integrity": "sha512-Pk3l3WOgM9joguZY2k52+jH82RtABRgB5RdGFZNUGbOKGMVlNmafcPA3b0ITcCZPu1L9UclP1tne6aw7ZI4Myg==", + "dependencies": { + "base64-js": "^1.5.1" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -13643,11 +13992,15 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -13871,6 +14224,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/logform": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.1.tgz", + "integrity": "sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -14738,6 +15107,61 @@ "lodash": "^4.17.21" } }, + "node_modules/mongodb-rag-core": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/mongodb-rag-core/-/mongodb-rag-core-0.4.1.tgz", + "integrity": "sha512-McgQyKeex2e2qR8PNo4zmn5XEAnPs5jmdtRZn5f9GAY1tQGjN+JS7ePYgLKwsEDUxRsR56rrtn9ExJgdFo9gFg==", + "dependencies": { + "@azure/openai": "^1.0.0-beta.5", + "@langchain/anthropic": "^0.2.15", + "@langchain/core": "^0.2.27", + "@langchain/openai": "^0.2.7", + "common-tags": "^1", + "dotenv": "^16.3.1", + "exponential-backoff": "^3.1.1", + "front-matter": "^4.0.2", + "gray-matter": "^4.0.3", + "mongodb": "^6.3.0", + "openai": "^3", + "toml": "^3.0.0", + "typechat": "^0.0.10", + "winston": "^3", + "yaml": "^2.3.1", + "zod": "^3.21.4" + }, + "engines": { + "node": ">=18", + "npm": ">=8" + } + }, + "node_modules/mongodb-rag-core/node_modules/axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "dependencies": { + "follow-redirects": "^1.14.8" + } + }, + "node_modules/mongodb-rag-core/node_modules/openai": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-3.3.0.tgz", + "integrity": "sha512-uqxI/Au+aPRnsaQRe8CojU0eCR7I0mBiKjD3sNMzY6DaC1ZVrc85u98mtJW6voDug8fgGN+DIZmTDxTthxb7dQ==", + "dependencies": { + "axios": "^0.26.0", + "form-data": "^4.0.0" + } + }, + "node_modules/mongodb-rag-core/node_modules/yaml": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", + "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/mongodb-redact": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/mongodb-redact/-/mongodb-redact-1.1.3.tgz", @@ -14934,6 +15358,14 @@ "object-assign": "^4.1.0" } }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "bin": { + "mustache": "bin/mustache" + } + }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -15601,6 +16033,14 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -15633,14 +16073,13 @@ } }, "node_modules/openai": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.57.0.tgz", - "integrity": "sha512-JnwBSIYqiZ3jYjB5f2in8hQ0PRA092c6m+/6dYB0MzK0BEbn+0dioxZsPLBm5idJbg9xzLNOiGVm2OSuhZ+BdQ==", - "dev": true, + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.59.0.tgz", + "integrity": "sha512-3bn7FypMt2R1ZDuO0+GcXgBEnVFhIzrpUkb47pQRoYvyfdZ2fQXcuP14aOc4C8F9FvCtZ/ElzJmVzVqnP4nHNg==", "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", - "@types/qs": "^6.9.7", + "@types/qs": "^6.9.15", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", @@ -15664,7 +16103,6 @@ "version": "18.19.48", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.48.tgz", "integrity": "sha512-7WevbG4ekUcRQSZzOwxWgi5dZmTak7FaxXDoW7xVxPBmKx1rTzfmRLkeCgJzcbBnOV2dkhAPc8cCeT6agocpjg==", - "dev": true, "dependencies": { "undici-types": "~5.26.4" } @@ -15852,6 +16290,14 @@ "node": ">=8" } }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "engines": { + "node": ">=4" + } + }, "node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -15879,6 +16325,44 @@ "node": ">=8" } }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -16494,6 +16978,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -17128,6 +17617,14 @@ "node": ">=8" } }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -17379,6 +17876,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -17432,6 +17937,18 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/seek-bzip": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", @@ -17457,9 +17974,9 @@ "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==" }, "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -17708,6 +18225,19 @@ "simple-concat": "^1.0.0" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/sinon": { "version": "9.2.4", "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.4.tgz", @@ -18045,6 +18575,14 @@ "nan": "^2.18.0" } }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, "node_modules/stackframe": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", @@ -18363,6 +18901,14 @@ "node": ">=8" } }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/strip-dirs": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", @@ -18799,6 +19345,11 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -18911,6 +19462,11 @@ "node": ">=0.6" } }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" + }, "node_modules/totalist": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", @@ -18957,6 +19513,14 @@ "node": ">=18" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/ts-loader": { "version": "9.5.1", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", @@ -19156,6 +19720,30 @@ "node": ">= 0.6" } }, + "node_modules/typechat": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/typechat/-/typechat-0.0.10.tgz", + "integrity": "sha512-iF/wLLaZWt4Q9WO8stpq3NKilAa4b8hnCD16EirdhaxzAYk80MCb1wnW1il7GhkMNJuhJUD38dxs8q4A/EdxJw==", + "dependencies": { + "axios": "^1.4.0", + "typescript": "^5.1.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/typechat/node_modules/typescript": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/typed-array-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", @@ -19264,8 +19852,7 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/universal-user-agent": { "version": "6.0.1", @@ -19865,6 +20452,93 @@ "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", "dev": true }, + "node_modules/winston": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.14.2.tgz", + "integrity": "sha512-CO8cdpBB2yqzEf8v895L+GNKYJiEq8eKlHU38af3snQBQ+sdAIUepjMSguOIJC7ICbzm0ZI+Af2If4vIJrtmOg==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.6.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.7.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.1.tgz", + "integrity": "sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA==", + "dependencies": { + "logform": "^2.6.1", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/winston-transport/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/winston/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/winston/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/winston/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/wipe-node-cache": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/wipe-node-cache/-/wipe-node-cache-2.1.2.tgz", @@ -20163,18 +20837,6 @@ "node": ">=10" } }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/yargs-unparser/node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -20231,6 +20893,14 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zod-to-json-schema": { + "version": "3.23.3", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.3.tgz", + "integrity": "sha512-TYWChTxKQbRJp5ST22o/Irt9KC5nj7CdBKYB/AosCRdj/wxEMvv4NNaj9XVUHDOIp53ZxArGhnw5HMZziPFjog==", + "peerDependencies": { + "zod": "^3.23.3" + } } } } diff --git a/package.json b/package.json index 7b742b4a9..b133b7370 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,11 @@ "name": "query", "isSticky": true, "description": "Ask how to write MongoDB queries or pipelines. For example, you can ask: \"Show me all the documents where the address contains the word street\"." + }, + { + "name": "docs", + "isSticky": true, + "description": "Ask MongoDB-related questions and find answers in the official documentation." } ] } @@ -1186,6 +1191,7 @@ "mongodb-data-service": "^22.23.0", "mongodb-log-writer": "^1.4.2", "mongodb-query-parser": "^4.2.2", + "mongodb-rag-core": "^0.4.1", "mongodb-schema": "^12.2.0", "numeral": "^2.0.6", "react": "^18.3.1", diff --git a/src/participant/docsChatbotAIService.ts b/src/participant/docsChatbotAIService.ts new file mode 100644 index 000000000..606690e25 --- /dev/null +++ b/src/participant/docsChatbotAIService.ts @@ -0,0 +1,154 @@ +import type { Reference, VerifiedAnswer } from 'mongodb-rag-core'; + +const MONGODB_DOCS_CHATBOT_BASE_URI = + process.env.MONGODB_DOCS_CHATBOT_BASE_URI || 'http://localhost:3000'; + +const DEFAULT_HEADERS = { + origin: MONGODB_DOCS_CHATBOT_BASE_URI, + 'User-Agent': 'mongodb-vscode/version', +}; + +export type Role = 'user' | 'assistant'; + +export type MessageData = { + id: string; + role: Role; + content: string; + createdAt: string; + rating?: boolean; + references?: Reference[]; + suggestedPrompts?: string[]; + metadata?: AssistantMessageMetadata; +}; + +export type AssistantMessageMetadata = { + [k: string]: unknown; + + /** + If the message came from the verified answers collection, contains the + metadata about the verified answer. + */ + verifiedAnswer?: { + _id: VerifiedAnswer['_id']; + created: string; + updated: string | undefined; + }; +}; + +export const CUSTOM_REQUEST_ORIGIN_HEADER = 'X-Request-Origin'; + +export function getCustomRequestOrigin(): string | undefined { + if (typeof window !== 'undefined') { + return window.location.href; + } + return undefined; +} + +export class RetriableError extends Error { + retryAfter: number; + data?: Data; + + constructor( + message: string, + config: { retryAfter?: number; data?: Data } = {} + ) { + const { retryAfter = 1000, data } = config; + super(message); + this.name = 'RetriableError'; + this.message = message; + this.retryAfter = retryAfter; + this.data = data; + } +} + +export class TimeoutError extends Error { + data?: Data; + + constructor(message: string) { + super(message); + this.name = 'TimeoutError'; + this.message = message; + } +} + +/** + Options to include with every fetch request made by the ConversationService. + This can be used to set headers, etc. + */ +export type ConversationFetchOptions = Omit< + RequestInit, + 'body' | 'method' | 'headers' | 'signal' +> & { + headers?: Headers; +}; + +export type ConversationServiceConfig = { + serverUrl: string; + fetchOptions?: ConversationFetchOptions; +}; + +export class DocsChatbotAIService { + constructor() {} + + private getUrl(path: string): string { + return MONGODB_DOCS_CHATBOT_BASE_URI + path; + } + + async createConversation(): Promise { + const path = '/api/v1/conversations'; + const resp = await fetch(this.getUrl(path), { + headers: DEFAULT_HEADERS, + method: 'POST', + }); + const conversation = await resp.json(); + if (resp.status === 400) { + throw new Error(`Bad request: ${conversation.error}`); + } + if (resp.status === 429) { + // TODO: Handle rate limiting + throw new Error(`Rate limited: ${conversation.error}`); + } + if (resp.status >= 500) { + throw new Error(`Server error: ${conversation.error}`); + } + return { + ...conversation, + conversationId: conversation._id, + }; + } + + async addMessage({ + conversationId, + message, + }: { + conversationId: string; + message: string; + }): Promise { + const path = `/api/v1/conversations/${conversationId}/messages`; + const resp = await fetch(this.getUrl(path), { + headers: { + ...DEFAULT_HEADERS, + 'Content-Type': 'application/json', + }, + method: 'POST', + body: JSON.stringify({ message }), + }); + const data = await resp.json(); + if (resp.status === 400) { + throw new Error(data.error); + } + if (resp.status === 404) { + throw new Error(`Conversation not found: ${data.error}`); + } + if (resp.status === 429) { + throw new Error(`Rate limited: ${data.error}`); + } + if (resp.status === 504) { + throw new TimeoutError(data.error); + } + if (resp.status >= 500) { + throw new Error(`Server error: ${data.error}`); + } + return data; + } +} diff --git a/src/participant/participant.ts b/src/participant/participant.ts index de958f678..71e80e9e1 100644 --- a/src/participant/participant.ts +++ b/src/participant/participant.ts @@ -15,6 +15,7 @@ import { COL_NAME_ID, DB_NAME_ID, NamespacePrompt } from './prompts/namespace'; import { SchemaFormatter } from './schema'; import { getSimplifiedSampleDocuments } from './sampleDocuments'; import { getCopilotModel } from './model'; +import { DocsChatbotAIService } from './docsChatbotAIService'; const log = createLogger('participant'); @@ -74,6 +75,7 @@ export default class ParticipantController { _collectionName?: string; _schema?: string; _sampleDocuments?: Document[]; + _docsChatbotAIService: DocsChatbotAIService; constructor({ connectionController, @@ -84,6 +86,7 @@ export default class ParticipantController { }) { this._connectionController = connectionController; this._storageController = storageController; + this._docsChatbotAIService = new DocsChatbotAIService(); } _setDatabaseName(name: string | undefined): void { @@ -283,12 +286,12 @@ export default class ParticipantController { name: string; }): vscode.MarkdownString { const commandQuery = query ? `?%5B%22${query}%22%5D` : ''; - const connName = new vscode.MarkdownString( + const link = new vscode.MarkdownString( `- ${name}\n` ); - connName.supportHtml = true; - connName.isTrusted = { enabledCommands: [commandId] }; - return connName; + link.supportHtml = true; + link.isTrusted = { enabledCommands: [commandId] }; + return link; } getConnectionsTree(): vscode.MarkdownString[] { @@ -733,6 +736,66 @@ export default class ParticipantController { return { metadata: { responseContent: runnableContent } }; } + async getDocumentationFromUserInput(message: string): Promise<{ + content: string; + references?: { + url: string; + title: string; + }[]; + }> { + try { + const conversation = + await this._docsChatbotAIService.createConversation(); + const response = await this._docsChatbotAIService.addMessage({ + message, + conversationId: conversation._id, + }); + return { + content: response.content, + references: response.references?.map((ref) => ({ + url: ref.url, + title: ref.title, + })), + }; + } catch (error) { + const errorMessage = + // eslint-disable-next-line no-nested-ternary + typeof error === 'string' + ? error + : error instanceof Error + ? error.message + : 'Сonversation вailed.'; + throw new Error(errorMessage); + } + } + + async handleDocsRequest( + request: vscode.ChatRequest, + context: vscode.ChatContext, + stream: vscode.ChatResponseStream, + token: vscode.CancellationToken + ): Promise { + const abortController = new AbortController(); + token.onCancellationRequested(() => { + abortController.abort(); + }); + + const response = await this.getDocumentationFromUserInput(request.prompt); + + stream.markdown(response.content); + if (response.references) { + for (const ref of response.references) { + const link = new vscode.MarkdownString( + `- ${ref.title}\n` + ); + link.supportHtml = true; + stream.markdown(link); + } + } + + return { metadata: { responseContent: response.content } }; + } + async chatHandler( ...args: [ vscode.ChatRequest, @@ -770,7 +833,7 @@ export default class ParticipantController { if (request.command === 'query') { this._chatResult = await this.handleQueryRequest(...args); } else if (request.command === 'docs') { - // TODO(VSCODE-570): Implement this. + this._chatResult = await this.handleDocsRequest(...args); } else if (request.command === 'schema') { // TODO(VSCODE-571): Implement this. } else { From 982411af42b81c9609fa6673dc4eea430b0c445a Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Fri, 13 Sep 2024 13:00:49 +0200 Subject: [PATCH 02/14] feat: use conversationId from history --- src/participant/docsChatbotAIService.ts | 11 +++---- src/participant/participant.ts | 44 +++++++++++++++++++++---- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/participant/docsChatbotAIService.ts b/src/participant/docsChatbotAIService.ts index 606690e25..4d915496d 100644 --- a/src/participant/docsChatbotAIService.ts +++ b/src/participant/docsChatbotAIService.ts @@ -1,7 +1,6 @@ import type { Reference, VerifiedAnswer } from 'mongodb-rag-core'; -const MONGODB_DOCS_CHATBOT_BASE_URI = - process.env.MONGODB_DOCS_CHATBOT_BASE_URI || 'http://localhost:3000'; +const MONGODB_DOCS_CHATBOT_BASE_URI = 'http://localhost:3000/'; const DEFAULT_HEADERS = { origin: MONGODB_DOCS_CHATBOT_BASE_URI, @@ -88,14 +87,12 @@ export type ConversationServiceConfig = { }; export class DocsChatbotAIService { - constructor() {} - private getUrl(path: string): string { - return MONGODB_DOCS_CHATBOT_BASE_URI + path; + return MONGODB_DOCS_CHATBOT_BASE_URI + 'api/v1' + path; } async createConversation(): Promise { - const path = '/api/v1/conversations'; + const path = '/conversations'; const resp = await fetch(this.getUrl(path), { headers: DEFAULT_HEADERS, method: 'POST', @@ -124,7 +121,7 @@ export class DocsChatbotAIService { conversationId: string; message: string; }): Promise { - const path = `/api/v1/conversations/${conversationId}/messages`; + const path = `/conversations/${conversationId}/messages`; const resp = await fetch(this.getUrl(path), { headers: { ...DEFAULT_HEADERS, diff --git a/src/participant/participant.ts b/src/participant/participant.ts index 71e80e9e1..33c8b13e9 100644 --- a/src/participant/participant.ts +++ b/src/participant/participant.ts @@ -33,6 +33,7 @@ const NUM_DOCUMENTS_TO_SAMPLE = 3; interface ChatResult extends vscode.ChatResult { metadata: { responseContent?: string; + conversationId?: string; }; } @@ -736,7 +737,14 @@ export default class ParticipantController { return { metadata: { responseContent: runnableContent } }; } - async getDocumentationFromUserInput(message: string): Promise<{ + async getDocumentationFromUserInput({ + message, + conversationId, + }: { + message: string; + conversationId: string; + }): Promise<{ + conversationId: string; content: string; references?: { url: string; @@ -744,13 +752,18 @@ export default class ParticipantController { }[]; }> { try { - const conversation = - await this._docsChatbotAIService.createConversation(); + if (!conversationId) { + const conversation = + await this._docsChatbotAIService.createConversation(); + conversationId = conversation.conversationId; + } + const response = await this._docsChatbotAIService.addMessage({ message, - conversationId: conversation._id, + conversationId, }); return { + conversationId, content: response.content, references: response.references?.map((ref) => ({ url: ref.url, @@ -780,7 +793,21 @@ export default class ParticipantController { abortController.abort(); }); - const response = await this.getDocumentationFromUserInput(request.prompt); + const historyWithConversationId = context.history.find((historyItem) => { + return ( + historyItem.participant === CHAT_PARTICIPANT_ID && + historyItem instanceof vscode.ChatResponseTurn && + historyItem.result.metadata?.conversationId + ); + }); + const conversationId = historyWithConversationId + ? (historyWithConversationId as vscode.ChatResponseTurn).result.metadata + ?.conversationId + : undefined; + const response = await this.getDocumentationFromUserInput({ + message: request.prompt, + conversationId, + }); stream.markdown(response.content); if (response.references) { @@ -793,7 +820,12 @@ export default class ParticipantController { } } - return { metadata: { responseContent: response.content } }; + return { + metadata: { + responseContent: response.content, + conversationId: response.conversationId, + }, + }; } async chatHandler( From 5366c44502e3ab2dd38fe1178e19587a1dacd7f2 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Fri, 13 Sep 2024 13:19:06 +0200 Subject: [PATCH 03/14] feat: use version in user-agent --- src/participant/docsChatbotAIService.ts | 51 ++++--------------------- 1 file changed, 7 insertions(+), 44 deletions(-) diff --git a/src/participant/docsChatbotAIService.ts b/src/participant/docsChatbotAIService.ts index 4d915496d..32284a7cc 100644 --- a/src/participant/docsChatbotAIService.ts +++ b/src/participant/docsChatbotAIService.ts @@ -2,9 +2,14 @@ import type { Reference, VerifiedAnswer } from 'mongodb-rag-core'; const MONGODB_DOCS_CHATBOT_BASE_URI = 'http://localhost:3000/'; +const MONGODB_DOCS_CHATBOT_API_VERSION = 'v1'; + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { version } = require('../../package.json'); + const DEFAULT_HEADERS = { origin: MONGODB_DOCS_CHATBOT_BASE_URI, - 'User-Agent': 'mongodb-vscode/version', + 'User-Agent': `mongodb-vscode/${version}`, }; export type Role = 'user' | 'assistant'; @@ -34,32 +39,6 @@ export type AssistantMessageMetadata = { }; }; -export const CUSTOM_REQUEST_ORIGIN_HEADER = 'X-Request-Origin'; - -export function getCustomRequestOrigin(): string | undefined { - if (typeof window !== 'undefined') { - return window.location.href; - } - return undefined; -} - -export class RetriableError extends Error { - retryAfter: number; - data?: Data; - - constructor( - message: string, - config: { retryAfter?: number; data?: Data } = {} - ) { - const { retryAfter = 1000, data } = config; - super(message); - this.name = 'RetriableError'; - this.message = message; - this.retryAfter = retryAfter; - this.data = data; - } -} - export class TimeoutError extends Error { data?: Data; @@ -70,25 +49,9 @@ export class TimeoutError extends Error { } } -/** - Options to include with every fetch request made by the ConversationService. - This can be used to set headers, etc. - */ -export type ConversationFetchOptions = Omit< - RequestInit, - 'body' | 'method' | 'headers' | 'signal' -> & { - headers?: Headers; -}; - -export type ConversationServiceConfig = { - serverUrl: string; - fetchOptions?: ConversationFetchOptions; -}; - export class DocsChatbotAIService { private getUrl(path: string): string { - return MONGODB_DOCS_CHATBOT_BASE_URI + 'api/v1' + path; + return `${MONGODB_DOCS_CHATBOT_BASE_URI}api/${MONGODB_DOCS_CHATBOT_API_VERSION}${path}`; } async createConversation(): Promise { From e05e1c9a728950f3e4f6ec19d5572305c8343864 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Mon, 16 Sep 2024 16:27:01 +0200 Subject: [PATCH 04/14] test: add tests for DocsChatbotAIService --- package.json | 4 +- ...erate-keyfile.ts => generate-constants.ts} | 13 ++- src/mdbExtensionController.ts | 1 + src/participant/docsChatbotAIService.ts | 105 ++++++++++------- src/participant/participant.ts | 45 +++++++- src/telemetry/telemetryService.ts | 14 ++- .../participant/docsChatbotAIService.test.ts | 108 ++++++++++++++++++ .../suite/participant/participant.test.ts | 1 + 8 files changed, 237 insertions(+), 54 deletions(-) rename scripts/{generate-keyfile.ts => generate-constants.ts} (66%) create mode 100644 src/test/suite/participant/docsChatbotAIService.test.ts diff --git a/package.json b/package.json index b133b7370..fa3e2b14e 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "update-grammar": "ts-node ./scripts/update-grammar.ts", "precompile": "npm run clean", "compile": "npm-run-all compile:*", - "compile:keyfile": "ts-node ./scripts/generate-keyfile.ts", + "compile:constants": "ts-node ./scripts/generate-constants.ts", "compile:resources": "npm run update-grammar", "compile:extension": "tsc -p ./", "compile:extension-bundles": "webpack --mode development", @@ -56,7 +56,7 @@ "test-webview": "mocha -r ts-node/register --file ./src/test/setup-webview.ts src/test/suite/views/webview-app/**/*.test.tsx", "ai-accuracy-tests": "mocha -r ts-node/register --file ./src/test/ai-accuracy-tests/test-setup.ts ./src/test/ai-accuracy-tests/ai-accuracy-tests.ts", "analyze-bundle": "webpack --mode production --analyze", - "vscode:prepublish": "npm run clean && npm run compile:keyfile && npm run compile:resources && webpack --mode production", + "vscode:prepublish": "npm run clean && npm run compile:constants && npm run compile:resources && webpack --mode production", "check": "npm run lint && npm run depcheck", "depcheck": "depcheck", "package": "cross-env NODE_OPTIONS='--require ./scripts/no-npm-list-fail.js' vsce package --githubBranch main", diff --git a/scripts/generate-keyfile.ts b/scripts/generate-constants.ts similarity index 66% rename from scripts/generate-keyfile.ts rename to scripts/generate-constants.ts index b7a6add73..7dc7c4ebf 100644 --- a/scripts/generate-keyfile.ts +++ b/scripts/generate-constants.ts @@ -9,15 +9,22 @@ import { promisify } from 'util'; const writeFile = promisify(fs.writeFile); const ROOT_DIR = path.join(__dirname, '..'); -const ui = ora('Generate constants keyfile').start(); +const ui = ora('Generate constants file').start(); config({ path: resolve(__dirname, '../.env') }); (async () => { - if (process.env.SEGMENT_KEY) { + if (process.env.SEGMENT_KEY || process.env.MONGODB_DOCS_CHATBOT_BASE_URI) { await writeFile( `${ROOT_DIR}/constants.json`, - JSON.stringify({ segmentKey: process.env.SEGMENT_KEY }, null, 2) + JSON.stringify( + { + segmentKey: process.env.SEGMENT_KEY, + docsChatbotBaseUri: process.env.MONGODB_DOCS_CHATBOT_BASE_URI, + }, + null, + 2 + ) ); ui.succeed('Generated segment constants file'); } else { diff --git a/src/mdbExtensionController.ts b/src/mdbExtensionController.ts index 9574ae6f8..8c881b6ef 100644 --- a/src/mdbExtensionController.ts +++ b/src/mdbExtensionController.ts @@ -120,6 +120,7 @@ export default class MDBExtensionController implements vscode.Disposable { this._playgroundSelectedCodeActionProvider, }); this._participantController = new ParticipantController({ + context, connectionController: this._connectionController, storageController: this._storageController, }); diff --git a/src/participant/docsChatbotAIService.ts b/src/participant/docsChatbotAIService.ts index 32284a7cc..f6f0829ed 100644 --- a/src/participant/docsChatbotAIService.ts +++ b/src/participant/docsChatbotAIService.ts @@ -1,19 +1,19 @@ import type { Reference, VerifiedAnswer } from 'mongodb-rag-core'; -const MONGODB_DOCS_CHATBOT_BASE_URI = 'http://localhost:3000/'; - const MONGODB_DOCS_CHATBOT_API_VERSION = 'v1'; // eslint-disable-next-line @typescript-eslint/no-var-requires const { version } = require('../../package.json'); -const DEFAULT_HEADERS = { - origin: MONGODB_DOCS_CHATBOT_BASE_URI, - 'User-Agent': `mongodb-vscode/${version}`, -}; - export type Role = 'user' | 'assistant'; +export type ConversationData = { + _id: string; + createdAt: string; + messages: MessageData[]; + conversationId: string; +}; + export type MessageData = { id: string; role: Role; @@ -50,26 +50,70 @@ export class TimeoutError extends Error { } export class DocsChatbotAIService { - private getUrl(path: string): string { - return `${MONGODB_DOCS_CHATBOT_BASE_URI}api/${MONGODB_DOCS_CHATBOT_API_VERSION}${path}`; + _serverBaseUri?: string; + + constructor(serverBaseUri?: string) { + this._serverBaseUri = serverBaseUri; + } + + private getServerBaseUri(): string { + if (!this._serverBaseUri) { + throw new Error( + 'You must define a serverBaseUri for the DocsChatbotAIService' + ); + } + return this._serverBaseUri; + } + + private getUri(path: string): string { + const serverBaseUri = this.getServerBaseUri(); + return `${serverBaseUri}api/${MONGODB_DOCS_CHATBOT_API_VERSION}${path}`; } - async createConversation(): Promise { - const path = '/conversations'; - const resp = await fetch(this.getUrl(path), { - headers: DEFAULT_HEADERS, + async createConversation(): Promise { + const uri = this.getUri('/conversation'); + return this._fetch({ + uri, method: 'POST', }); - const conversation = await resp.json(); + } + + async _fetch({ + uri, + method, + body, + headers, + }: { + uri: string; + method: string; + body?: string; + headers?: { [key: string]: string }; + }): Promise { + const resp = await fetch(uri, { + headers: { + origin: this.getServerBaseUri(), + 'User-Agent': `mongodb-vscode/${version}`, + ...headers, + }, + method, + ...(body && { body }), + }); + + let conversation; + try { + conversation = await resp.json(); + } catch (error) { + throw new Error('Internal server error'); + } + if (resp.status === 400) { throw new Error(`Bad request: ${conversation.error}`); } if (resp.status === 429) { - // TODO: Handle rate limiting throw new Error(`Rate limited: ${conversation.error}`); } if (resp.status >= 500) { - throw new Error(`Server error: ${conversation.error}`); + throw new Error(`Internal server error: ${conversation.error}`); } return { ...conversation, @@ -84,31 +128,12 @@ export class DocsChatbotAIService { conversationId: string; message: string; }): Promise { - const path = `/conversations/${conversationId}/messages`; - const resp = await fetch(this.getUrl(path), { - headers: { - ...DEFAULT_HEADERS, - 'Content-Type': 'application/json', - }, + const uri = this.getUri(`/conversations/${conversationId}/messages`); + return (await this._fetch({ + uri, method: 'POST', body: JSON.stringify({ message }), - }); - const data = await resp.json(); - if (resp.status === 400) { - throw new Error(data.error); - } - if (resp.status === 404) { - throw new Error(`Conversation not found: ${data.error}`); - } - if (resp.status === 429) { - throw new Error(`Rate limited: ${data.error}`); - } - if (resp.status === 504) { - throw new TimeoutError(data.error); - } - if (resp.status >= 500) { - throw new Error(`Server error: ${data.error}`); - } - return data; + headers: { 'Content-Type': 'application/json' }, + })) as MessageData; } } diff --git a/src/participant/participant.ts b/src/participant/participant.ts index 33c8b13e9..165d3d9c6 100644 --- a/src/participant/participant.ts +++ b/src/participant/participant.ts @@ -1,6 +1,9 @@ import * as vscode from 'vscode'; import { getSimplifiedSchema } from 'mongodb-schema'; import type { Document } from 'bson'; +import { config } from 'dotenv'; +import path from 'path'; +import fs from 'fs'; import { createLogger } from '../logging'; import type ConnectionController from '../connectionController'; @@ -68,6 +71,7 @@ export function getRunnableContentFromString(text: string): string { export default class ParticipantController { _participant?: vscode.ChatParticipant; + _context: vscode.ExtensionContext; _connectionController: ConnectionController; _storageController: StorageController; _queryGenerationState?: QUERY_GENERATION_STATE; @@ -81,13 +85,46 @@ export default class ParticipantController { constructor({ connectionController, storageController, + context, }: { connectionController: ConnectionController; storageController: StorageController; + context: vscode.ExtensionContext; }) { + this._context = context; this._connectionController = connectionController; this._storageController = storageController; - this._docsChatbotAIService = new DocsChatbotAIService(); + + const docsChatbotBaseUri = this._readDocsChatbotBaseUri(); + this._docsChatbotAIService = new DocsChatbotAIService(docsChatbotBaseUri); + } + + private _readDocsChatbotBaseUri(): string | undefined { + config({ path: path.join(this._context.extensionPath, '.env') }); + + try { + const docsChatbotBaseUriFileLocation = path.join( + this._context.extensionPath, + './constants.json' + ); + // eslint-disable-next-line no-sync + const constantsFile = fs.readFileSync( + docsChatbotBaseUriFileLocation, + 'utf8' + ); + const constants = JSON.parse(constantsFile) as { + docsChatbotBaseUri: string; + }; + + log.info('docsChatbotBaseUri was found', { + type: typeof constants.docsChatbotBaseUri, + }); + + return constants.docsChatbotBaseUri; + } catch (error) { + log.error('docsChatbotBaseUri was not found', error); + return; + } } _setDatabaseName(name: string | undefined): void { @@ -755,7 +792,7 @@ export default class ParticipantController { if (!conversationId) { const conversation = await this._docsChatbotAIService.createConversation(); - conversationId = conversation.conversationId; + conversationId = conversation._id; } const response = await this._docsChatbotAIService.addMessage({ @@ -823,7 +860,9 @@ export default class ParticipantController { return { metadata: { responseContent: response.content, - conversationId: response.conversationId, + ...(response.conversationId && { + conversationId: response.conversationId, + }), }, }; } diff --git a/src/telemetry/telemetryService.ts b/src/telemetry/telemetryService.ts index f3bcb1bf4..45e4d49a3 100644 --- a/src/telemetry/telemetryService.ts +++ b/src/telemetry/telemetryService.ts @@ -164,7 +164,7 @@ export default class TelemetryService { const constantsFile = fs.readFileSync(segmentKeyFileLocation, 'utf8'); const constants = JSON.parse(constantsFile) as { segmentKey: string }; - log.info('SegmentKey was found', { type: typeof constants.segmentKey }); + log.info('segmentKey was found', { type: typeof constants.segmentKey }); return constants.segmentKey; } catch (error) { @@ -215,7 +215,7 @@ export default class TelemetryService { return true; } - _segmentAnalyticsTrack(segmentProperties: SegmentProperties) { + _segmentAnalyticsTrack(segmentProperties: SegmentProperties): void { if (!this._isTelemetryFeatureEnabled()) { return; } @@ -250,7 +250,7 @@ export default class TelemetryService { async _getConnectionTelemetryProperties( dataService: DataService, connectionType: ConnectionTypes - ) { + ): Promise { return await getConnectionTelemetryProperties(dataService, connectionType); } @@ -298,7 +298,9 @@ export default class TelemetryService { return 'other'; } - getTelemetryUserIdentity() { + getTelemetryUserIdentity(): { + anonymousId: string; + } { return { anonymousId: this._segmentAnonymousId, }; @@ -363,7 +365,7 @@ export default class TelemetryService { trackSavedConnectionsLoaded( savedConnectionsLoadedProps: SavedConnectionsLoadedProperties - ) { + ): void { this.track( TelemetryEventTypes.SAVED_CONNECTIONS_LOADED, savedConnectionsLoadedProps @@ -372,7 +374,7 @@ export default class TelemetryService { trackKeytarSecretsMigrationFailed( keytarSecretsMigrationFailedProps: KeytarSecretsMigrationFailedProperties - ) { + ): void { this.track( TelemetryEventTypes.KEYTAR_SECRETS_MIGRATION_FAILED, keytarSecretsMigrationFailedProps diff --git a/src/test/suite/participant/docsChatbotAIService.test.ts b/src/test/suite/participant/docsChatbotAIService.test.ts new file mode 100644 index 000000000..8a5f33d2a --- /dev/null +++ b/src/test/suite/participant/docsChatbotAIService.test.ts @@ -0,0 +1,108 @@ +import { beforeEach, afterEach } from 'mocha'; +import { expect } from 'chai'; +import sinon from 'sinon'; + +import { DocsChatbotAIService } from '../../../participant/docsChatbotAIService'; + +suite('DocsChatbotAIService Test Suite', function () { + const initialFetch = global.fetch; + + afterEach(function () { + global.fetch = initialFetch; + sinon.restore(); + }); + + suite('when serverBaseUri is missing', function () { + test('does not crash the extension on launch', () => { + const docsChatbotAIService = new DocsChatbotAIService(); + expect(docsChatbotAIService._serverBaseUri).to.be.undefined; + }); + + test('throws if serverBaseUri is not set', async () => { + const docsChatbotAIService = new DocsChatbotAIService(); + try { + await docsChatbotAIService.createConversation(); + expect.fail('It must fail with missing serverBaseUri'); + } catch (error) { + expect((error as Error).message).to.include( + 'You must define a serverBaseUri for the DocsChatbotAIService' + ); + } + }); + }); + + suite('when serverBaseUri is present', function () { + const serverBaseUri = 'https://example.com/'; + let docsChatbotAIService: DocsChatbotAIService; + + beforeEach(() => { + docsChatbotAIService = new DocsChatbotAIService(serverBaseUri); + }); + + test('creates conversations', async () => { + const fetchStub = sinon.stub().resolves({ + status: 200, + ok: true, + json: () => + Promise.resolve({ + _id: '650b4b260f975ef031016c8a', + messages: [], + }), + }); + global.fetch = fetchStub; + const conversation = await docsChatbotAIService.createConversation(); + expect(conversation._id).to.be.eql('650b4b260f975ef031016c8a'); + }); + + test('throws on server errors', async () => { + const fetchStub = sinon.stub().resolves({ + status: 500, + ok: false, + statusText: 'Server error', + json: sinon.stub().rejects(new Error('invalid json')), + }); + global.fetch = fetchStub; + + try { + await docsChatbotAIService.createConversation(); + expect.fail('It must fail with the server error'); + } catch (error) { + expect((error as Error).message).to.include('Internal server error'); + } + }); + + test('throws on bad requests', async () => { + const fetchStub = sinon.stub().resolves({ + status: 400, + ok: false, + statusText: 'Client error', + json: sinon.stub().resolves({}), + }); + global.fetch = fetchStub; + + try { + await docsChatbotAIService.createConversation(); + expect.fail('It must fail with the bad request error'); + } catch (error) { + expect((error as Error).message).to.include('Bad request'); + } + }); + + test('throws on a rate limit', async () => { + const fetchStub = sinon.stub().resolves({ + status: 429, + ok: false, + statusText: 'Model error', + json: sinon.stub().resolves({}), + }); + global.fetch = fetchStub; + + try { + await docsChatbotAIService.createConversation(); + expect.fail('It must fail with the rate limited error'); + } catch (error) { + expect((error as Error).message).to.include('Rate limited'); + } + }); + }); +}); diff --git a/src/test/suite/participant/participant.test.ts b/src/test/suite/participant/participant.test.ts index 761524a44..cf1df0c11 100644 --- a/src/test/suite/participant/participant.test.ts +++ b/src/test/suite/participant/participant.test.ts @@ -65,6 +65,7 @@ suite('Participant Controller Test Suite', function () { telemetryService: testTelemetryService, }); testParticipantController = new ParticipantController({ + context: extensionContextStub, connectionController: testConnectionController, storageController: testStorageController, }); From 9f21b1a5b213a308b3ea55a1a5081e6a63935eb2 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Mon, 16 Sep 2024 17:44:24 +0200 Subject: [PATCH 05/14] refactor: fix type --- src/participant/docsChatbotAIService.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/participant/docsChatbotAIService.ts b/src/participant/docsChatbotAIService.ts index f6f0829ed..3f0a05f0f 100644 --- a/src/participant/docsChatbotAIService.ts +++ b/src/participant/docsChatbotAIService.ts @@ -78,7 +78,7 @@ export class DocsChatbotAIService { }); } - async _fetch({ + async _fetch({ uri, method, body, @@ -88,7 +88,7 @@ export class DocsChatbotAIService { method: string; body?: string; headers?: { [key: string]: string }; - }): Promise { + }): Promise { const resp = await fetch(uri, { headers: { origin: this.getServerBaseUri(), @@ -129,11 +129,11 @@ export class DocsChatbotAIService { message: string; }): Promise { const uri = this.getUri(`/conversations/${conversationId}/messages`); - return (await this._fetch({ + return await this._fetch({ uri, method: 'POST', body: JSON.stringify({ message }), headers: { 'Content-Type': 'application/json' }, - })) as MessageData; + }); } } From fb974ce63c281f0009b9a117bd129f20d99f4fbf Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Mon, 16 Sep 2024 17:49:47 +0200 Subject: [PATCH 06/14] refactor: update messages --- scripts/generate-constants.ts | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/scripts/generate-constants.ts b/scripts/generate-constants.ts index 7dc7c4ebf..19c738210 100644 --- a/scripts/generate-constants.ts +++ b/scripts/generate-constants.ts @@ -14,22 +14,18 @@ const ui = ora('Generate constants file').start(); config({ path: resolve(__dirname, '../.env') }); (async () => { - if (process.env.SEGMENT_KEY || process.env.MONGODB_DOCS_CHATBOT_BASE_URI) { - await writeFile( - `${ROOT_DIR}/constants.json`, - JSON.stringify( - { - segmentKey: process.env.SEGMENT_KEY, - docsChatbotBaseUri: process.env.MONGODB_DOCS_CHATBOT_BASE_URI, - }, - null, - 2 - ) - ); - ui.succeed('Generated segment constants file'); - } else { - throw new Error('The Segment key is missing in environment variables'); - } + await writeFile( + `${ROOT_DIR}/constants.json`, + JSON.stringify( + { + segmentKey: process.env.SEGMENT_KEY, + docsChatbotBaseUri: process.env.MONGODB_DOCS_CHATBOT_BASE_URI, + }, + null, + 2 + ) + ); + ui.succeed('The constants file has been generated'); })().catch((error) => { - ui.fail(`Failed to generate segment constants file: ${error.message}`); + ui.fail(`Failed to generate constants file: ${error.message}`); }); From b696d0c5aa741c8539c960b56aa54f4c63363d3c Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Mon, 16 Sep 2024 17:58:33 +0200 Subject: [PATCH 07/14] refactor: cleanup --- src/participant/docsChatbotAIService.ts | 10 ---------- src/participant/participant.ts | 18 +++++++++--------- src/telemetry/telemetryService.ts | 11 +++++------ .../participant/docsChatbotAIService.test.ts | 4 ++-- 4 files changed, 16 insertions(+), 27 deletions(-) diff --git a/src/participant/docsChatbotAIService.ts b/src/participant/docsChatbotAIService.ts index 3f0a05f0f..26bef4461 100644 --- a/src/participant/docsChatbotAIService.ts +++ b/src/participant/docsChatbotAIService.ts @@ -39,16 +39,6 @@ export type AssistantMessageMetadata = { }; }; -export class TimeoutError extends Error { - data?: Data; - - constructor(message: string) { - super(message); - this.name = 'TimeoutError'; - this.message = message; - } -} - export class DocsChatbotAIService { _serverBaseUri?: string; diff --git a/src/participant/participant.ts b/src/participant/participant.ts index 165d3d9c6..7466391ca 100644 --- a/src/participant/participant.ts +++ b/src/participant/participant.ts @@ -112,17 +112,15 @@ export default class ParticipantController { docsChatbotBaseUriFileLocation, 'utf8' ); - const constants = JSON.parse(constantsFile) as { - docsChatbotBaseUri: string; + const { docsChatbotBaseUri } = JSON.parse(constantsFile) as { + docsChatbotBaseUri?: string; }; - - log.info('docsChatbotBaseUri was found', { - type: typeof constants.docsChatbotBaseUri, - }); - - return constants.docsChatbotBaseUri; + return docsChatbotBaseUri; } catch (error) { - log.error('docsChatbotBaseUri was not found', error); + log.error( + 'Failed to read docsChatbotBaseUri from the constants file', + error + ); return; } } @@ -830,6 +828,8 @@ export default class ParticipantController { abortController.abort(); }); + // TODO: update this part when the PR with chatId is merged + // https://github.com/mongodb-js/vscode/pull/810 const historyWithConversationId = context.history.find((historyItem) => { return ( historyItem.participant === CHAT_PARTICIPANT_ID && diff --git a/src/telemetry/telemetryService.ts b/src/telemetry/telemetryService.ts index 45e4d49a3..1891391aa 100644 --- a/src/telemetry/telemetryService.ts +++ b/src/telemetry/telemetryService.ts @@ -162,13 +162,12 @@ export default class TelemetryService { ); // eslint-disable-next-line no-sync const constantsFile = fs.readFileSync(segmentKeyFileLocation, 'utf8'); - const constants = JSON.parse(constantsFile) as { segmentKey: string }; - - log.info('segmentKey was found', { type: typeof constants.segmentKey }); - - return constants.segmentKey; + const { segmentKey } = JSON.parse(constantsFile) as { + segmentKey?: string; + }; + return segmentKey; } catch (error) { - log.error('SegmentKey was not found', error); + log.error('Failed to read segmentKey from the constants file', error); return; } } diff --git a/src/test/suite/participant/docsChatbotAIService.test.ts b/src/test/suite/participant/docsChatbotAIService.test.ts index 8a5f33d2a..6860c7a0b 100644 --- a/src/test/suite/participant/docsChatbotAIService.test.ts +++ b/src/test/suite/participant/docsChatbotAIService.test.ts @@ -13,12 +13,12 @@ suite('DocsChatbotAIService Test Suite', function () { }); suite('when serverBaseUri is missing', function () { - test('does not crash the extension on launch', () => { + test('DocsChatbotAIService constructor does not throw', () => { const docsChatbotAIService = new DocsChatbotAIService(); expect(docsChatbotAIService._serverBaseUri).to.be.undefined; }); - test('throws if serverBaseUri is not set', async () => { + test('createConversation throws if serverBaseUri is not set', async () => { const docsChatbotAIService = new DocsChatbotAIService(); try { await docsChatbotAIService.createConversation(); From 0ea60d207cc6787a73f19d089997a60bccd5b877 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Tue, 17 Sep 2024 14:13:05 +0200 Subject: [PATCH 08/14] feat: fall back to copilot when chatbot is not available --- src/participant/docsChatbotAIService.ts | 9 +- src/participant/participant.ts | 124 +++++++++++++++--------- 2 files changed, 85 insertions(+), 48 deletions(-) diff --git a/src/participant/docsChatbotAIService.ts b/src/participant/docsChatbotAIService.ts index 26bef4461..2a444ea6f 100644 --- a/src/participant/docsChatbotAIService.ts +++ b/src/participant/docsChatbotAIService.ts @@ -88,7 +88,6 @@ export class DocsChatbotAIService { method, ...(body && { body }), }); - let conversation; try { conversation = await resp.json(); @@ -97,13 +96,15 @@ export class DocsChatbotAIService { } if (resp.status === 400) { - throw new Error(`Bad request: ${conversation.error}`); + throw new Error(`[Docs chatbot] Bad request: ${conversation.error}`); } if (resp.status === 429) { - throw new Error(`Rate limited: ${conversation.error}`); + throw new Error(`[Docs chatbot] Rate limited: ${conversation.error}`); } if (resp.status >= 500) { - throw new Error(`Internal server error: ${conversation.error}`); + throw new Error( + `[Docs chatbot] Internal server error: ${conversation.error}` + ); } return { ...conversation, diff --git a/src/participant/participant.ts b/src/participant/participant.ts index 7466391ca..6f4d5df7d 100644 --- a/src/participant/participant.ts +++ b/src/participant/participant.ts @@ -33,6 +33,8 @@ export enum QUERY_GENERATION_STATE { const NUM_DOCUMENTS_TO_SAMPLE = 3; +const MONGODB_DOCS_LINK = 'https://www.mongodb.com/docs/'; + interface ChatResult extends vscode.ChatResult { metadata: { responseContent?: string; @@ -786,43 +788,32 @@ export default class ParticipantController { title: string; }[]; }> { - try { - if (!conversationId) { - const conversation = - await this._docsChatbotAIService.createConversation(); - conversationId = conversation._id; - } + const conversation = await this._docsChatbotAIService.createConversation(); + conversationId = conversation._id; - const response = await this._docsChatbotAIService.addMessage({ - message, - conversationId, - }); - return { - conversationId, - content: response.content, - references: response.references?.map((ref) => ({ - url: ref.url, - title: ref.title, - })), - }; - } catch (error) { - const errorMessage = - // eslint-disable-next-line no-nested-ternary - typeof error === 'string' - ? error - : error instanceof Error - ? error.message - : 'Сonversation вailed.'; - throw new Error(errorMessage); - } + const response = await this._docsChatbotAIService.addMessage({ + message, + conversationId, + }); + return { + conversationId, + content: response.content, + references: response.references?.map((ref) => ({ + url: ref.url, + title: ref.title, + })), + }; } async handleDocsRequest( - request: vscode.ChatRequest, - context: vscode.ChatContext, - stream: vscode.ChatResponseStream, - token: vscode.CancellationToken + ...args: [ + vscode.ChatRequest, + vscode.ChatContext, + vscode.ChatResponseStream, + vscode.CancellationToken + ] ): Promise { + const [request, context, stream, token] = args; const abortController = new AbortController(); token.onCancellationRequested(() => { abortController.abort(); @@ -837,18 +828,65 @@ export default class ParticipantController { historyItem.result.metadata?.conversationId ); }); - const conversationId = historyWithConversationId + let conversationId = historyWithConversationId ? (historyWithConversationId as vscode.ChatResponseTurn).result.metadata ?.conversationId : undefined; - const response = await this.getDocumentationFromUserInput({ - message: request.prompt, - conversationId, - }); - stream.markdown(response.content); - if (response.references) { - for (const ref of response.references) { + let responseContent; + let responseReferences; + try { + const response = await this.getDocumentationFromUserInput({ + message: request.prompt, + conversationId, + }); + responseContent = response.content; + responseReferences = response.references; + conversationId = response.conversationId; + } catch (error) { + log.error(error); + + // If the docs chatbot API is not available, fall back to Copilot’s LLM and include + // the MongoDB documentation link for users to go to our documentation site directly. + const messages = GenericPrompt.buildMessages({ + request, + context, + }); + + const abortController = new AbortController(); + token.onCancellationRequested(() => { + abortController.abort(); + }); + responseContent = await this.getChatResponseContent({ + messages, + stream, + token, + }); + responseReferences = [ + { + url: MONGODB_DOCS_LINK, + title: 'View MongoDB documentation', + }, + ]; + } + + stream.markdown(responseContent); + + const runnableContent = getRunnableContentFromString(responseContent); + if (runnableContent && runnableContent.trim().length) { + stream.button({ + command: EXTENSION_COMMANDS.RUN_PARTICIPANT_QUERY, + title: vscode.l10n.t('▶️ Run'), + }); + + stream.button({ + command: EXTENSION_COMMANDS.OPEN_PARTICIPANT_QUERY_IN_PLAYGROUND, + title: vscode.l10n.t('Open in playground'), + }); + } + + if (responseReferences) { + for (const ref of responseReferences) { const link = new vscode.MarkdownString( `- ${ref.title}\n` ); @@ -859,10 +897,8 @@ export default class ParticipantController { return { metadata: { - responseContent: response.content, - ...(response.conversationId && { - conversationId: response.conversationId, - }), + responseContent, + ...(conversationId && { conversationId }), }, }; } From 72ff3329c11c63fcdce58779bf092641b553334d Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Wed, 18 Sep 2024 11:50:39 +0200 Subject: [PATCH 09/14] test: add fallback test --- src/participant/participant.ts | 3 +++ .../suite/participant/participant.test.ts | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/participant/participant.ts b/src/participant/participant.ts index 3f2ce8d83..bf97c1ebf 100644 --- a/src/participant/participant.ts +++ b/src/participant/participant.ts @@ -92,6 +92,9 @@ export default class ParticipantController { this._docsChatbotAIService = new DocsChatbotAIService(docsChatbotBaseUri); } + // To integrate with the MongoDB documentation chatbot, + // set the MONGODB_DOCS_CHATBOT_BASE_URI environment variable when running the extension from a branch. + // This variable is automatically injected during the .vsix build process via GitHub Actions. private _readDocsChatbotBaseUri(): string | undefined { config({ path: path.join(this._context.extensionPath, '.env') }); diff --git a/src/test/suite/participant/participant.test.ts b/src/test/suite/participant/participant.test.ts index 69a97ab08..c6c6d95a9 100644 --- a/src/test/suite/participant/participant.test.ts +++ b/src/test/suite/participant/participant.test.ts @@ -1091,6 +1091,29 @@ suite('Participant Controller Test Suite', function () { }); }); }); + + suite('docs command', function () { + beforeEach(function () { + sendRequestStub.onCall(0).resolves({ + text: ['connection info'], + }); + }); + + test('falls back to the generic command when docs chatbot api is not available', async function () { + const chatRequestMock = { + prompt: 'how to connect to mongodb', + command: 'docs', + references: [], + }; + await testParticipantController.chatHandler( + chatRequestMock, + chatContextStub, + chatStreamStub, + chatTokenStub + ); + expect(sendRequestStub).to.have.been.called; + }); + }); }); }); }); From 3d2139ea0de1d316345844e17be282c3bd8b973d Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Wed, 18 Sep 2024 12:00:56 +0200 Subject: [PATCH 10/14] build: add docs chatbot env variable --- .github/workflows/draft-release.yaml | 1 + .github/workflows/test-and-build.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/draft-release.yaml b/.github/workflows/draft-release.yaml index 2246bc3ac..62ec8fb49 100644 --- a/.github/workflows/draft-release.yaml +++ b/.github/workflows/draft-release.yaml @@ -80,6 +80,7 @@ jobs: uses: ./.github/workflows/actions/test-and-build with: SEGMENT_KEY: ${{ secrets.SEGMENT_KEY_PROD }} + MONGODB_DOCS_CHATBOT_BASE_URI: ${{ secrets.MONGODB_DOCS_CHATBOT_BASE_URI_PROD }} ARTIFACTORY_HOST: ${{ secrets.ARTIFACTORY_HOST }} ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }} diff --git a/.github/workflows/test-and-build.yaml b/.github/workflows/test-and-build.yaml index ceaaa04f3..73fc6ef88 100644 --- a/.github/workflows/test-and-build.yaml +++ b/.github/workflows/test-and-build.yaml @@ -36,6 +36,7 @@ jobs: uses: ./.github/workflows/actions/test-and-build with: SEGMENT_KEY: ${{ secrets.SEGMENT_KEY_PROD }} + MONGODB_DOCS_CHATBOT_BASE_URI: ${{ secrets.MONGODB_DOCS_CHATBOT_BASE_URI_PROD }} ARTIFACTORY_HOST: ${{ secrets.ARTIFACTORY_HOST }} ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }} From ad0973db9038fab9c3837b8dfb510302f2a106fc Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Wed, 18 Sep 2024 12:21:11 +0200 Subject: [PATCH 11/14] refactor: update log message --- src/participant/docsChatbotAIService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/participant/docsChatbotAIService.ts b/src/participant/docsChatbotAIService.ts index 13fbfc893..cfad679fc 100644 --- a/src/participant/docsChatbotAIService.ts +++ b/src/participant/docsChatbotAIService.ts @@ -92,7 +92,7 @@ export class DocsChatbotAIService { try { conversation = await resp.json(); } catch (error) { - throw new Error('Internal server error'); + throw new Error('[Docs chatbot] Internal server error'); } if (resp.status === 400) { From d40e10e4cd1800b227cee3d7b17f9f05b807e9a1 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Wed, 18 Sep 2024 17:47:03 +0200 Subject: [PATCH 12/14] chore: move mongodb-rag-core to dev deps --- package-lock.json | 135 +++++++++++++++++++++++++++++++++++++++------- package.json | 2 +- 2 files changed, 117 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index 685ee56a1..b97830f6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,7 +35,6 @@ "mongodb-data-service": "^22.23.0", "mongodb-log-writer": "^1.4.2", "mongodb-query-parser": "^4.2.2", - "mongodb-rag-core": "^0.4.1", "mongodb-schema": "^12.2.0", "numeral": "^2.0.6", "react": "^18.3.1", @@ -95,6 +94,7 @@ "mocha-junit-reporter": "^2.2.1", "mocha-multi": "^1.1.7", "mongodb-client-encryption": "^6.0.1", + "mongodb-rag-core": "^0.4.1", "mongodb-runner": "^5.6.4", "node-fetch": "^2.7.0", "node-loader": "^0.6.0", @@ -151,6 +151,7 @@ "version": "0.25.2", "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.25.2.tgz", "integrity": "sha512-F1Hck/asswwidFLtGdMg3XYgRxEUfygNbpkq5KEaEGsHNaSfxeX18/uZGQCL0oQNcj/tYNx8BaFXVwRhFDi45g==", + "dev": true, "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", @@ -165,6 +166,7 @@ "version": "18.19.50", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.50.tgz", "integrity": "sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==", + "dev": true, "dependencies": { "undici-types": "~5.26.4" } @@ -884,6 +886,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/@azure-rest/core-client/-/core-client-1.4.0.tgz", "integrity": "sha512-ozTDPBVUDR5eOnMIwhggbnVmOrka4fXCs8n8mvUo4WLLc38kki6bAOByDoVZZPz/pZy2jMt2kwfpvy/UjALj6w==", + "dev": true, "dependencies": { "@azure/abort-controller": "^2.0.0", "@azure/core-auth": "^1.3.0", @@ -900,6 +903,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dev": true, "dependencies": { "tslib": "^2.6.2" }, @@ -923,6 +927,7 @@ "version": "1.7.2", "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz", "integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==", + "dev": true, "dependencies": { "@azure/abort-controller": "^2.0.0", "@azure/core-util": "^1.1.0", @@ -936,6 +941,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dev": true, "dependencies": { "tslib": "^2.6.2" }, @@ -977,6 +983,7 @@ "version": "1.16.1", "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.1.tgz", "integrity": "sha512-ExPSbgjwCoht6kB7B4MeZoBAxcQSIl29r/bPeazZJx50ej4JJCByimLOrZoIsurISNyJQQHf30b3JfqC3Hb88A==", + "dev": true, "dependencies": { "@azure/abort-controller": "^2.0.0", "@azure/core-auth": "^1.4.0", @@ -995,6 +1002,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dev": true, "dependencies": { "tslib": "^2.6.2" }, @@ -1006,6 +1014,7 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dev": true, "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -1018,6 +1027,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/@azure/core-sse/-/core-sse-2.1.3.tgz", "integrity": "sha512-KSSdIKy8kvWCpYr8Hzpu22j3wcXsVTYE0IlgmI1T/aHvBDsLgV91y90UTfVWnuiuApRLCCVC4gS09ApBGOmYQA==", + "dev": true, "dependencies": { "tslib": "^2.6.2" }, @@ -1029,6 +1039,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.1.2.tgz", "integrity": "sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA==", + "dev": true, "dependencies": { "tslib": "^2.6.2" }, @@ -1040,6 +1051,7 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.9.0.tgz", "integrity": "sha512-AfalUQ1ZppaKuxPPMsFEUdX6GZPB3d9paR9d/TTL7Ow2De8cJaC7ibi7kWVlFAVPCYo31OcnGymc0R89DX8Oaw==", + "dev": true, "dependencies": { "@azure/abort-controller": "^2.0.0", "tslib": "^2.6.2" @@ -1052,6 +1064,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dev": true, "dependencies": { "tslib": "^2.6.2" }, @@ -1114,6 +1127,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.2.tgz", "integrity": "sha512-l170uE7bsKpIU6B/giRc9i4NI0Mj+tANMMMxf7Zi/5cKzEqPayP7+X1WPrG7e+91JgY8N+7K7nF2WOi7iVhXvg==", + "dev": true, "dependencies": { "tslib": "^2.6.2" }, @@ -1160,6 +1174,7 @@ "version": "1.0.0-beta.12", "resolved": "https://registry.npmjs.org/@azure/openai/-/openai-1.0.0-beta.12.tgz", "integrity": "sha512-qKblxr6oVa8GsyNzY+/Ub9VmEsPYKhBrUrPaNEQiM+qrxnBPVm9kaeqGFFb/U78Q2zOabmhF9ctYt3xBW0nWnQ==", + "dev": true, "dependencies": { "@azure-rest/core-client": "^1.1.7", "@azure/core-auth": "^1.4.0", @@ -1830,6 +1845,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "dev": true, "engines": { "node": ">=0.1.90" } @@ -1860,6 +1876,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dev": true, "dependencies": { "colorspace": "1.1.x", "enabled": "2.0.x", @@ -2372,6 +2389,7 @@ "version": "0.2.18", "resolved": "https://registry.npmjs.org/@langchain/anthropic/-/anthropic-0.2.18.tgz", "integrity": "sha512-4ZDTxMwGKTPRAi2Supu/faBSmwPIm/ga5QlazyO78Mf/8QbDR2DcvM5394FAy+X/nRAfnMbyXteO5IRJm653gw==", + "dev": true, "dependencies": { "@anthropic-ai/sdk": "^0.25.2", "@langchain/core": ">=0.2.21 <0.3.0", @@ -2387,6 +2405,7 @@ "version": "0.2.32", "resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.2.32.tgz", "integrity": "sha512-S27M+9Qou2qtcLfFGEvANkJ/zHq5XApeQsR6Q4I7C6v9x07eoYr558h6vVy6WQmKcksgbCIJ854ikwp173wBjA==", + "dev": true, "dependencies": { "ansi-styles": "^5.0.0", "camelcase": "6", @@ -2407,12 +2426,14 @@ "node_modules/@langchain/core/node_modules/@types/uuid": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==" + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true }, "node_modules/@langchain/core/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "engines": { "node": ">=10" }, @@ -2424,6 +2445,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -2432,6 +2454,7 @@ "version": "0.1.55", "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.1.55.tgz", "integrity": "sha512-6NVtI04UUnIY59I/imOX02FG/QMGfqStu8tiJtyyreKMv2GAN0EE9Z5Ap1wzOe6v8ukEcV3NwEO2LYOPwup1PQ==", + "dev": true, "dependencies": { "@types/uuid": "^10.0.0", "commander": "^10.0.1", @@ -2461,6 +2484,7 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "dev": true, "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -2473,6 +2497,7 @@ "version": "0.2.10", "resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-0.2.10.tgz", "integrity": "sha512-ph5sYDAmhP55Fs3TW3+LXiqF+r/5zaaNO2tur9p2Otr8KWNDSgp5ezfPki1WWfuUJVoSQ+6HDYtr6n2V5N1Lew==", + "dev": true, "dependencies": { "@langchain/core": ">=0.2.26 <0.3.0", "js-tiktoken": "^1.0.12", @@ -6010,6 +6035,7 @@ "version": "2.6.11", "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "dev": true, "dependencies": { "@types/node": "*", "form-data": "^4.0.0" @@ -6028,7 +6054,8 @@ "node_modules/@types/qs": { "version": "6.9.15", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==" + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "dev": true }, "node_modules/@types/react": { "version": "17.0.80", @@ -6083,7 +6110,8 @@ "node_modules/@types/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true }, "node_modules/@types/scheduler": { "version": "0.16.3", @@ -6142,7 +6170,8 @@ "node_modules/@types/triple-beam": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "dev": true }, "node_modules/@types/use-sync-external-store": { "version": "0.0.3", @@ -7051,6 +7080,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, "dependencies": { "event-target-shim": "^5.0.0" }, @@ -7115,6 +7145,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dev": true, "dependencies": { "humanize-ms": "^1.2.1" }, @@ -7423,12 +7454,14 @@ "node_modules/async": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true }, "node_modules/available-typed-arrays": { "version": "1.0.5", @@ -7450,6 +7483,7 @@ "version": "1.7.7", "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "dev": true, "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -8113,6 +8147,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, "engines": { "node": ">=10" }, @@ -8431,6 +8466,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dev": true, "dependencies": { "color-convert": "^1.9.3", "color-string": "^1.6.0" @@ -8456,6 +8492,7 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dev": true, "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -8465,6 +8502,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -8472,7 +8510,8 @@ "node_modules/color/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true }, "node_modules/colorette": { "version": "2.0.20", @@ -8493,6 +8532,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dev": true, "dependencies": { "color": "^3.1.3", "text-hex": "1.0.x" @@ -8502,6 +8542,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -8513,6 +8554,7 @@ "version": "10.0.1", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, "engines": { "node": ">=14" } @@ -8521,6 +8563,7 @@ "version": "1.8.2", "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, "engines": { "node": ">=4.0.0" } @@ -9404,6 +9447,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, "engines": { "node": ">=0.4.0" } @@ -9967,7 +10011,8 @@ "node_modules/enabled": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "dev": true }, "node_modules/encodeurl": { "version": "1.0.2", @@ -11110,6 +11155,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, "engines": { "node": ">=6" } @@ -11227,7 +11273,8 @@ "node_modules/exponential-backoff": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==" + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true }, "node_modules/express": { "version": "4.19.2", @@ -11287,6 +11334,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, "dependencies": { "is-extendable": "^0.1.0" }, @@ -11442,7 +11490,8 @@ "node_modules/fecha": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "dev": true }, "node_modules/fetch-blob": { "version": "3.2.0", @@ -11620,7 +11669,8 @@ "node_modules/fn.name": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "dev": true }, "node_modules/focus-trap": { "version": "6.9.4", @@ -11648,6 +11698,7 @@ "version": "1.15.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "dev": true, "funding": [ { "type": "individual", @@ -11810,6 +11861,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -11822,12 +11874,14 @@ "node_modules/form-data-encoder": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", - "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "dev": true }, "node_modules/formdata-node": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dev": true, "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "4.0.0-beta.3" @@ -11840,6 +11894,7 @@ "version": "4.0.0-beta.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "dev": true, "engines": { "node": ">= 14" } @@ -11876,6 +11931,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", + "dev": true, "dependencies": { "js-yaml": "^3.13.1" } @@ -12326,6 +12382,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "dev": true, "dependencies": { "js-yaml": "^3.13.1", "kind-of": "^6.0.2", @@ -12799,6 +12856,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, "dependencies": { "ms": "^2.0.0" } @@ -13340,6 +13398,7 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -13728,6 +13787,7 @@ "version": "1.0.14", "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.14.tgz", "integrity": "sha512-Pk3l3WOgM9joguZY2k52+jH82RtABRgB5RdGFZNUGbOKGMVlNmafcPA3b0ITcCZPu1L9UclP1tne6aw7ZI4Myg==", + "dev": true, "dependencies": { "base64-js": "^1.5.1" } @@ -14067,6 +14127,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -14074,7 +14135,8 @@ "node_modules/kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "dev": true }, "node_modules/leven": { "version": "3.1.0", @@ -14303,6 +14365,7 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.1.tgz", "integrity": "sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA==", + "dev": true, "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", @@ -15186,6 +15249,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/mongodb-rag-core/-/mongodb-rag-core-0.4.1.tgz", "integrity": "sha512-McgQyKeex2e2qR8PNo4zmn5XEAnPs5jmdtRZn5f9GAY1tQGjN+JS7ePYgLKwsEDUxRsR56rrtn9ExJgdFo9gFg==", + "dev": true, "dependencies": { "@azure/openai": "^1.0.0-beta.5", "@langchain/anthropic": "^0.2.15", @@ -15213,6 +15277,7 @@ "version": "0.26.1", "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "dev": true, "dependencies": { "follow-redirects": "^1.14.8" } @@ -15221,6 +15286,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/openai/-/openai-3.3.0.tgz", "integrity": "sha512-uqxI/Au+aPRnsaQRe8CojU0eCR7I0mBiKjD3sNMzY6DaC1ZVrc85u98mtJW6voDug8fgGN+DIZmTDxTthxb7dQ==", + "dev": true, "dependencies": { "axios": "^0.26.0", "form-data": "^4.0.0" @@ -15230,6 +15296,7 @@ "version": "2.5.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", + "dev": true, "bin": { "yaml": "bin.mjs" }, @@ -15437,6 +15504,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true, "bin": { "mustache": "bin/mustache" } @@ -16124,6 +16192,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dev": true, "dependencies": { "fn.name": "1.x.x" } @@ -16163,6 +16232,7 @@ "version": "4.59.0", "resolved": "https://registry.npmjs.org/openai/-/openai-4.59.0.tgz", "integrity": "sha512-3bn7FypMt2R1ZDuO0+GcXgBEnVFhIzrpUkb47pQRoYvyfdZ2fQXcuP14aOc4C8F9FvCtZ/ElzJmVzVqnP4nHNg==", + "dev": true, "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", @@ -16190,6 +16260,7 @@ "version": "18.19.48", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.48.tgz", "integrity": "sha512-7WevbG4ekUcRQSZzOwxWgi5dZmTak7FaxXDoW7xVxPBmKx1rTzfmRLkeCgJzcbBnOV2dkhAPc8cCeT6agocpjg==", + "dev": true, "dependencies": { "undici-types": "~5.26.4" } @@ -16381,6 +16452,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, "engines": { "node": ">=4" } @@ -16416,6 +16488,7 @@ "version": "6.6.2", "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "dev": true, "dependencies": { "eventemitter3": "^4.0.4", "p-timeout": "^3.2.0" @@ -16431,6 +16504,7 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" @@ -16443,6 +16517,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, "dependencies": { "p-finally": "^1.0.0" }, @@ -17069,7 +17144,8 @@ "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true }, "node_modules/pseudomap": { "version": "1.0.2", @@ -17709,6 +17785,7 @@ "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, "engines": { "node": ">= 4" } @@ -17897,6 +17974,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "dev": true, "engines": { "node": ">=10" } @@ -17958,6 +18036,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "dev": true, "dependencies": { "extend-shallow": "^2.0.1", "kind-of": "^6.0.0" @@ -18246,6 +18325,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dev": true, "dependencies": { "is-arrayish": "^0.3.1" } @@ -18253,7 +18333,8 @@ "node_modules/simple-swizzle/node_modules/is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true }, "node_modules/sinon": { "version": "9.2.4", @@ -18596,6 +18677,7 @@ "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "dev": true, "engines": { "node": "*" } @@ -18922,6 +19004,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -19365,7 +19448,8 @@ "node_modules/text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "dev": true }, "node_modules/text-table": { "version": "0.2.0", @@ -19482,7 +19566,8 @@ "node_modules/toml": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", - "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "dev": true }, "node_modules/totalist": { "version": "3.0.1", @@ -19534,6 +19619,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "dev": true, "engines": { "node": ">= 14.0.0" } @@ -19741,6 +19827,7 @@ "version": "0.0.10", "resolved": "https://registry.npmjs.org/typechat/-/typechat-0.0.10.tgz", "integrity": "sha512-iF/wLLaZWt4Q9WO8stpq3NKilAa4b8hnCD16EirdhaxzAYk80MCb1wnW1il7GhkMNJuhJUD38dxs8q4A/EdxJw==", + "dev": true, "dependencies": { "axios": "^1.4.0", "typescript": "^5.1.3" @@ -19753,6 +19840,7 @@ "version": "5.6.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -19869,7 +19957,8 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true }, "node_modules/universal-user-agent": { "version": "6.0.1", @@ -20473,6 +20562,7 @@ "version": "3.14.2", "resolved": "https://registry.npmjs.org/winston/-/winston-3.14.2.tgz", "integrity": "sha512-CO8cdpBB2yqzEf8v895L+GNKYJiEq8eKlHU38af3snQBQ+sdAIUepjMSguOIJC7ICbzm0ZI+Af2If4vIJrtmOg==", + "dev": true, "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", @@ -20494,6 +20584,7 @@ "version": "4.7.1", "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.1.tgz", "integrity": "sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA==", + "dev": true, "dependencies": { "logform": "^2.6.1", "readable-stream": "^3.6.2", @@ -20507,6 +20598,7 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -20520,6 +20612,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -20528,6 +20621,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, "engines": { "node": ">=8" }, @@ -20539,6 +20633,7 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -20552,6 +20647,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -20915,6 +21011,7 @@ "version": "3.23.3", "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.3.tgz", "integrity": "sha512-TYWChTxKQbRJp5ST22o/Irt9KC5nj7CdBKYB/AosCRdj/wxEMvv4NNaj9XVUHDOIp53ZxArGhnw5HMZziPFjog==", + "dev": true, "peerDependencies": { "zod": "^3.23.3" } diff --git a/package.json b/package.json index fa3e2b14e..d977efaf2 100644 --- a/package.json +++ b/package.json @@ -1191,7 +1191,6 @@ "mongodb-data-service": "^22.23.0", "mongodb-log-writer": "^1.4.2", "mongodb-query-parser": "^4.2.2", - "mongodb-rag-core": "^0.4.1", "mongodb-schema": "^12.2.0", "numeral": "^2.0.6", "react": "^18.3.1", @@ -1208,6 +1207,7 @@ "@mongodb-js/oidc-mock-provider": "^0.9.1", "@mongodb-js/oidc-plugin": "^0.4.0", "@mongodb-js/prettier-config-devtools": "^1.0.1", + "mongodb-rag-core": "^0.4.1", "@mongodb-js/sbom-tools": "^0.7.1", "@mongodb-js/signing-utils": "^0.3.5", "@mongosh/service-provider-core": "^2.2.15", From f29a86bbb3a6bd93ff8bcf2d40ddd06253ec604d Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Thu, 19 Sep 2024 16:27:22 +0200 Subject: [PATCH 13/14] refactor: address pr comments --- src/mdbExtensionController.ts | 2 +- src/participant/docsChatbotAIService.ts | 8 +- src/participant/participant.ts | 246 +++++++++++------- .../suite/participant/participant.test.ts | 1 - 4 files changed, 150 insertions(+), 107 deletions(-) diff --git a/src/mdbExtensionController.ts b/src/mdbExtensionController.ts index 2fd83467b..98bbf9e7d 100644 --- a/src/mdbExtensionController.ts +++ b/src/mdbExtensionController.ts @@ -121,7 +121,6 @@ export default class MDBExtensionController implements vscode.Disposable { this._playgroundSelectedCodeActionProvider, }); this._participantController = new ParticipantController({ - context, connectionController: this._connectionController, storageController: this._storageController, telemetryService: this._telemetryService, @@ -156,6 +155,7 @@ export default class MDBExtensionController implements vscode.Disposable { this._telemetryService.activateSegmentAnalytics(); this._participantController.createParticipant(this._context); + await this._participantController.createDocsChatbot(this._context); await this._connectionController.loadSavedConnections(); await this._languageServerController.startLanguageServer(); diff --git a/src/participant/docsChatbotAIService.ts b/src/participant/docsChatbotAIService.ts index cfad679fc..d73de13f5 100644 --- a/src/participant/docsChatbotAIService.ts +++ b/src/participant/docsChatbotAIService.ts @@ -5,16 +5,16 @@ const MONGODB_DOCS_CHATBOT_API_VERSION = 'v1'; // eslint-disable-next-line @typescript-eslint/no-var-requires const { version } = require('../../package.json'); -export type Role = 'user' | 'assistant'; +type Role = 'user' | 'assistant'; -export type ConversationData = { +type ConversationData = { _id: string; createdAt: string; messages: MessageData[]; conversationId: string; }; -export type MessageData = { +type MessageData = { id: string; role: Role; content: string; @@ -25,7 +25,7 @@ export type MessageData = { metadata?: AssistantMessageMetadata; }; -export type AssistantMessageMetadata = { +type AssistantMessageMetadata = { [k: string]: unknown; /** diff --git a/src/participant/participant.ts b/src/participant/participant.ts index 45225d2f1..4776829d5 100644 --- a/src/participant/participant.ts +++ b/src/participant/participant.ts @@ -3,7 +3,7 @@ import { getSimplifiedSchema } from 'mongodb-schema'; import type { Document } from 'bson'; import { config } from 'dotenv'; import path from 'path'; -import fs from 'fs'; +import { promises as fs } from 'fs'; import { createLogger } from '../logging'; import type ConnectionController from '../connectionController'; @@ -32,6 +32,7 @@ import { ChatMetadataStore } from './chatMetadata'; import { DocsChatbotAIService } from './docsChatbotAIService'; import { chatResultFeedbackKindToTelemetryValue } from '../telemetry/telemetryService'; import type TelemetryService from '../telemetry/telemetryService'; +import type { Reference } from 'mongodb-rag-core'; const log = createLogger('participant'); @@ -74,47 +75,42 @@ export function getRunnableContentFromString(text: string): string { export default class ParticipantController { _participant?: vscode.ChatParticipant; - _context: vscode.ExtensionContext; _connectionController: ConnectionController; _storageController: StorageController; _chatMetadataStore: ChatMetadataStore; - _docsChatbotAIService: DocsChatbotAIService; + _docsChatbotAIService?: DocsChatbotAIService; _telemetryService: TelemetryService; constructor({ - context, connectionController, storageController, telemetryService, }: { - context: vscode.ExtensionContext; connectionController: ConnectionController; storageController: StorageController; telemetryService: TelemetryService; }) { - this._context = context; this._connectionController = connectionController; this._storageController = storageController; this._chatMetadataStore = new ChatMetadataStore(); this._telemetryService = telemetryService; - - const docsChatbotBaseUri = this._readDocsChatbotBaseUri(); - this._docsChatbotAIService = new DocsChatbotAIService(docsChatbotBaseUri); } // To integrate with the MongoDB documentation chatbot, // set the MONGODB_DOCS_CHATBOT_BASE_URI environment variable when running the extension from a branch. // This variable is automatically injected during the .vsix build process via GitHub Actions. - private _readDocsChatbotBaseUri(): string | undefined { - config({ path: path.join(this._context.extensionPath, '.env') }); + private async _readDocsChatbotBaseUri( + context: vscode.ExtensionContext + ): Promise { + config({ path: path.join(context.extensionPath, '.env') }); try { const docsChatbotBaseUriFileLocation = path.join( - this._context.extensionPath, + context.extensionPath, './constants.json' ); // eslint-disable-next-line no-sync - const constantsFile = fs.readFileSync( + const constantsFile = await fs.readFile( docsChatbotBaseUriFileLocation, 'utf8' ); @@ -151,6 +147,11 @@ export default class ParticipantController { return this._participant; } + async createDocsChatbot(context: vscode.ExtensionContext): Promise { + const docsChatbotBaseUri = await this._readDocsChatbotBaseUri(context); + this._docsChatbotAIService = new DocsChatbotAIService(docsChatbotBaseUri); + } + getParticipant(): vscode.ChatParticipant | undefined { return this._participant; } @@ -216,6 +217,31 @@ export default class ParticipantController { return responseContent; } + _streamRunnableContentToPlayground({ + responseContent, + stream, + }: { + responseContent: string; + stream: vscode.ChatResponseStream; + }): void { + const runnableContent = getRunnableContentFromString(responseContent); + if (runnableContent) { + const commandArgs: RunParticipantQueryCommandArgs = { + runnableContent, + }; + stream.button({ + command: EXTENSION_COMMANDS.RUN_PARTICIPANT_QUERY, + title: vscode.l10n.t('▶️ Run'), + arguments: [commandArgs], + }); + stream.button({ + command: EXTENSION_COMMANDS.OPEN_PARTICIPANT_QUERY_IN_PLAYGROUND, + title: vscode.l10n.t('Open in playground'), + arguments: [commandArgs], + }); + } + } + // @MongoDB what is mongodb? async handleGenericRequest( request: vscode.ChatRequest, @@ -239,22 +265,10 @@ export default class ParticipantController { }); stream.markdown(responseContent); - const runnableContent = getRunnableContentFromString(responseContent); - if (runnableContent) { - const commandArgs: RunParticipantQueryCommandArgs = { - runnableContent, - }; - stream.button({ - command: EXTENSION_COMMANDS.RUN_PARTICIPANT_QUERY, - title: vscode.l10n.t('▶️ Run'), - arguments: [commandArgs], - }); - stream.button({ - command: EXTENSION_COMMANDS.OPEN_PARTICIPANT_QUERY_IN_PLAYGROUND, - title: vscode.l10n.t('Open in playground'), - arguments: [commandArgs], - }); - } + this._streamRunnableContentToPlayground({ + responseContent, + stream, + }); return genericRequestChatResult(context.history); } @@ -771,24 +785,84 @@ export default class ParticipantController { stream.markdown(responseContent); - const runnableContent = getRunnableContentFromString(responseContent); - if (runnableContent) { - const commandArgs: RunParticipantQueryCommandArgs = { - runnableContent, - }; - stream.button({ - command: EXTENSION_COMMANDS.RUN_PARTICIPANT_QUERY, - title: vscode.l10n.t('▶️ Run'), - arguments: [commandArgs], - }); - stream.button({ - command: EXTENSION_COMMANDS.OPEN_PARTICIPANT_QUERY_IN_PLAYGROUND, - title: vscode.l10n.t('Open in playground'), - arguments: [commandArgs], + this._streamRunnableContentToPlayground({ + responseContent, + stream, + }); + + return queryRequestChatResult(context.history); + } + + async _handleDocsRequestWithChatbot({ + docsChatbotAIService, + prompt, + chatId, + }: { + docsChatbotAIService: DocsChatbotAIService; + prompt: string; + chatId: string; + }): Promise<{ + responseContent: string; + responseReferences?: Reference[]; + }> { + let { docsChatbotConversationId } = + this._chatMetadataStore.getChatMetadata(chatId) ?? {}; + if (!docsChatbotConversationId) { + const conversation = await docsChatbotAIService.createConversation(); + docsChatbotConversationId = conversation._id; + this._chatMetadataStore.setChatMetadata(chatId, { + docsChatbotConversationId, }); } - return queryRequestChatResult(context.history); + const response = await docsChatbotAIService.addMessage({ + message: prompt, + conversationId: docsChatbotConversationId, + }); + + return { + responseContent: response.content, + responseReferences: response.references, + }; + } + + async _handleDocsRequestWithCopilot( + ...args: [ + vscode.ChatRequest, + vscode.ChatContext, + vscode.ChatResponseStream, + vscode.CancellationToken + ] + ): Promise<{ + responseContent: string; + responseReferences?: Reference[]; + }> { + const [request, context, stream, token] = args; + const messages = GenericPrompt.buildMessages({ + request, + context, + }); + + const abortController = new AbortController(); + token.onCancellationRequested(() => { + abortController.abort(); + }); + const responseContent = await this.getChatResponseContent({ + messages, + stream, + token, + }); + const responseReferences = [ + { + url: MONGODB_DOCS_LINK, + title: 'View MongoDB documentation', + }, + ]; + + return { + responseContent, + responseReferences, + }; } async handleDocsRequest( @@ -809,71 +883,41 @@ export default class ParticipantController { context.history ); - let responseContent; - let responseReferences; - try { - let { docsChatbotConversationId } = - this._chatMetadataStore.getChatMetadata(chatId) ?? {}; - if (!docsChatbotConversationId) { - const conversation = - await this._docsChatbotAIService.createConversation(); - docsChatbotConversationId = conversation._id; - this._chatMetadataStore.setChatMetadata(chatId, { - docsChatbotConversationId, + let docsChatbotHasThrownError = false; + let docsResult: { + responseContent?: string; + responseReferences?: Reference[]; + } = {}; + + if (this._docsChatbotAIService) { + try { + docsResult = await this._handleDocsRequestWithChatbot({ + docsChatbotAIService: this._docsChatbotAIService, + prompt: request.prompt, + chatId, }); + } catch (error) { + // If the docs chatbot API is not available, fall back to Copilot’s LLM and include + // the MongoDB documentation link for users to go to our documentation site directly. + docsChatbotHasThrownError = true; + log.error(error); } - - const response = await this._docsChatbotAIService.addMessage({ - message: request.prompt, - conversationId: docsChatbotConversationId, - }); - - responseContent = response.content; - responseReferences = response.references; - } catch (error) { - log.error(error); - - // If the docs chatbot API is not available, fall back to Copilot’s LLM and include - // the MongoDB documentation link for users to go to our documentation site directly. - const messages = GenericPrompt.buildMessages({ - request, - context, - }); - - const abortController = new AbortController(); - token.onCancellationRequested(() => { - abortController.abort(); - }); - responseContent = await this.getChatResponseContent({ - messages, - stream, - token, - }); - responseReferences = [ - { - url: MONGODB_DOCS_LINK, - title: 'View MongoDB documentation', - }, - ]; } - stream.markdown(responseContent); - - const runnableContent = getRunnableContentFromString(responseContent); - if (runnableContent && runnableContent.trim().length) { - stream.button({ - command: EXTENSION_COMMANDS.RUN_PARTICIPANT_QUERY, - title: vscode.l10n.t('▶️ Run'), - }); + if (!this._docsChatbotAIService || docsChatbotHasThrownError) { + docsResult = await this._handleDocsRequestWithCopilot(...args); + } - stream.button({ - command: EXTENSION_COMMANDS.OPEN_PARTICIPANT_QUERY_IN_PLAYGROUND, - title: vscode.l10n.t('Open in playground'), + if (docsResult.responseContent) { + stream.markdown(docsResult.responseContent); + this._streamRunnableContentToPlayground({ + responseContent: docsResult.responseContent, + stream, }); } - if (responseReferences) { - for (const ref of responseReferences) { + if (docsResult.responseReferences) { + for (const ref of docsResult.responseReferences) { const link = new vscode.MarkdownString( `- ${ref.title}\n` ); diff --git a/src/test/suite/participant/participant.test.ts b/src/test/suite/participant/participant.test.ts index b5ddde659..3eea00a2d 100644 --- a/src/test/suite/participant/participant.test.ts +++ b/src/test/suite/participant/participant.test.ts @@ -69,7 +69,6 @@ suite('Participant Controller Test Suite', function () { telemetryService: testTelemetryService, }); testParticipantController = new ParticipantController({ - context: extensionContextStub, connectionController: testConnectionController, storageController: testStorageController, telemetryService: testTelemetryService, From 5f6c5f7cf7dfd7f76b52391a107aa906f512d5a0 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Thu, 19 Sep 2024 17:39:19 +0200 Subject: [PATCH 14/14] test: add test that uses chatbot --- src/participant/participant.ts | 10 ++--- .../suite/participant/participant.test.ts | 40 ++++++++++++++++++- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/participant/participant.ts b/src/participant/participant.ts index 45db7764a..4ccd57eff 100644 --- a/src/participant/participant.ts +++ b/src/participant/participant.ts @@ -102,7 +102,7 @@ export default class ParticipantController { // To integrate with the MongoDB documentation chatbot, // set the MONGODB_DOCS_CHATBOT_BASE_URI environment variable when running the extension from a branch. // This variable is automatically injected during the .vsix build process via GitHub Actions. - private async _readDocsChatbotBaseUri( + async _readDocsChatbotBaseUri( context: vscode.ExtensionContext ): Promise { config({ path: path.join(context.extensionPath, '.env') }); @@ -220,7 +220,7 @@ export default class ParticipantController { return responseContent; } - _streamRunnableContentToPlayground({ + _streamRunnableContentActions({ responseContent, stream, }: { @@ -268,7 +268,7 @@ export default class ParticipantController { }); stream.markdown(responseContent); - this._streamRunnableContentToPlayground({ + this._streamRunnableContentActions({ responseContent, stream, }); @@ -788,7 +788,7 @@ export default class ParticipantController { stream.markdown(responseContent); - this._streamRunnableContentToPlayground({ + this._streamRunnableContentActions({ responseContent, stream, }); @@ -913,7 +913,7 @@ export default class ParticipantController { if (docsResult.responseContent) { stream.markdown(docsResult.responseContent); - this._streamRunnableContentToPlayground({ + this._streamRunnableContentActions({ responseContent: docsResult.responseContent, stream, }); diff --git a/src/test/suite/participant/participant.test.ts b/src/test/suite/participant/participant.test.ts index 7f8c167fd..354a95a95 100644 --- a/src/test/suite/participant/participant.test.ts +++ b/src/test/suite/participant/participant.test.ts @@ -1057,19 +1057,57 @@ suite('Participant Controller Test Suite', function () { }); suite('docs command', function () { + const initialFetch = global.fetch; + let fetchStub; + + afterEach(function () { + global.fetch = initialFetch; + sinon.restore(); + }); + beforeEach(function () { + fetchStub = sinon.stub().resolves({ + status: 200, + ok: true, + json: () => + Promise.resolve({ + _id: '650b4b260f975ef031016c8a', + messages: [], + }), + }); + global.fetch = fetchStub; sendRequestStub.onCall(0).resolves({ text: ['connection info'], }); }); - test('falls back to the generic command when docs chatbot api is not available', async function () { + test('uses docs chatbot when it is available', async function () { + sinon.replace( + testParticipantController, + '_readDocsChatbotBaseUri', + sinon.stub().resolves('url') + ); + await testParticipantController.createDocsChatbot( + extensionContextStub + ); + const chatRequestMock = { + prompt: 'how to connect to mongodb', + command: 'docs', + references: [], + }; + await invokeChatHandler(chatRequestMock); + expect(fetchStub).to.have.been.called; + expect(sendRequestStub).to.have.not.been.called; + }); + + test('falls back to the copilot model when docs chatbot api is not available', async function () { const chatRequestMock = { prompt: 'how to connect to mongodb', command: 'docs', references: [], }; await invokeChatHandler(chatRequestMock); + expect(fetchStub).to.have.not.been.called; expect(sendRequestStub).to.have.been.called; }); });