From dd1a6bba1f08d0efbbf811fc3f5a2e5b11f8d6f1 Mon Sep 17 00:00:00 2001 From: MisterPapaye Date: Tue, 18 Nov 2025 20:41:59 +0100 Subject: [PATCH 01/11] initial branche commit => install google lib --- package-lock.json | 684 +++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + src/routes/api.ai.ts | 1 + 3 files changed, 686 insertions(+) diff --git a/package-lock.json b/package-lock.json index a300b45..57a35d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@clerk/clerk-sdk-node": "^4.13.23", "@clerk/express": "^1.7.13", + "@google/genai": "^1.30.0", "@modelcontextprotocol/sdk": "^1.20.2", "@tiptap/starter-kit": "^3.5.1", "@types/express": "^5.0.3", @@ -992,6 +993,44 @@ "node": ">=18" } }, + "node_modules/@google/genai": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.30.0.tgz", + "integrity": "sha512-3MRcgczBFbUat1wIlZoLJ0vCCfXgm7Qxjh59cZi2X08RgWLtm9hKOspzp7TOg1TV2e26/MLxR2GR5yD5GmBV2w==", + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^10.3.0", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.20.1" + }, + "peerDependenciesMeta": { + "@modelcontextprotocol/sdk": { + "optional": true + } + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@modelcontextprotocol/sdk": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.20.2.tgz", @@ -1054,6 +1093,16 @@ "node": ">=10.12.0" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@remirror/core-constants": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz", @@ -1688,6 +1737,30 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/anymatch": { "version": "3.1.3", "license": "ISC", @@ -1736,6 +1809,26 @@ "version": "1.0.2", "license": "MIT" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", @@ -1768,6 +1861,15 @@ "require-from-string": "^2.0.2" } }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "license": "MIT", @@ -1914,6 +2016,24 @@ "fsevents": "~2.3.2" } }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -2042,6 +2162,15 @@ "version": "3.1.3", "license": "MIT" }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/data-urls": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.0.tgz", @@ -2147,6 +2276,12 @@ "node": ">= 0.4" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "license": "Apache-2.0", @@ -2158,6 +2293,12 @@ "version": "1.1.1", "license": "MIT" }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, "node_modules/encodeurl": { "version": "2.0.0", "license": "MIT", @@ -2518,6 +2659,12 @@ "express": ">= 4.11" } }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2534,6 +2681,29 @@ "version": "1.3.0", "license": "Unlicense" }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/fill-range": { "version": "7.1.1", "license": "MIT", @@ -2559,6 +2729,22 @@ "node": ">= 0.8" } }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", @@ -2599,6 +2785,18 @@ "node": ">= 0.6" } }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "license": "MIT", @@ -2620,6 +2818,53 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gaxios": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.3.tgz", + "integrity": "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2", + "rimraf": "^5.0.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gaxios/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/generate-function": { "version": "2.3.1", "license": "MIT", @@ -2660,6 +2905,26 @@ "node": ">= 0.4" } }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "5.1.2", "license": "ISC", @@ -2674,6 +2939,78 @@ "version": "0.4.1", "license": "BSD-2-Clause" }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/google-auth-library": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.5.0.tgz", + "integrity": "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.0.0", + "gcp-metadata": "^8.0.0", + "google-logging-utils": "^1.0.0", + "gtoken": "^8.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-auth-library/node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/google-auth-library/node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, "node_modules/gopd": { "version": "1.2.0", "license": "MIT", @@ -2684,6 +3021,40 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gtoken": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-8.0.0.tgz", + "integrity": "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==", + "license": "MIT", + "dependencies": { + "gaxios": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gtoken/node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/gtoken/node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/has-flag": { "version": "3.0.0", "license": "MIT", @@ -2820,6 +3191,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "license": "MIT", @@ -2867,6 +3247,21 @@ "url": "https://github.com/sponsors/dmonad" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/js-cookie": { "version": "3.0.5", "license": "MIT", @@ -2920,6 +3315,15 @@ } } }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -3184,6 +3588,15 @@ "node": "*" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/morgan": { "version": "1.10.0", "license": "MIT", @@ -3287,6 +3700,26 @@ "tslib": "^2.0.3" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -3434,6 +3867,12 @@ "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", "license": "MIT" }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, "node_modules/parse5": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", @@ -3462,6 +3901,28 @@ "node": ">=8" } }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, "node_modules/path-to-regexp": { "version": "8.2.0", "license": "MIT", @@ -3844,6 +4305,21 @@ "node": ">=0.10.0" } }, + "node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/rope-sequence": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", @@ -4039,6 +4515,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/simple-update-notifier": { "version": "2.0.0", "license": "MIT", @@ -4294,6 +4782,102 @@ "version": "3.9.0", "license": "MIT" }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/stripe": { "version": "18.3.0", "license": "MIT", @@ -4528,6 +5112,15 @@ "node": ">=18" } }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/webcrypto-core": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.8.1.tgz", @@ -4599,6 +5192,97 @@ "node": ">= 8" } }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrappy": { "version": "1.0.2", "license": "ISC" diff --git a/package.json b/package.json index 1b230fa..ec21b58 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "dependencies": { "@clerk/clerk-sdk-node": "^4.13.23", "@clerk/express": "^1.7.13", + "@google/genai": "^1.30.0", "@modelcontextprotocol/sdk": "^1.20.2", "@tiptap/starter-kit": "^3.5.1", "@types/express": "^5.0.3", diff --git a/src/routes/api.ai.ts b/src/routes/api.ai.ts index 4986fea..a50b343 100644 --- a/src/routes/api.ai.ts +++ b/src/routes/api.ai.ts @@ -1,6 +1,7 @@ import { UUID, randomUUID } from 'crypto'; import { Router, Request, Response, NextFunction } from 'express'; import OpenAI from "openai"; +import { GoogleGenAI } from "@google/genai"; import fs from 'fs'; import path from 'path'; import __dirname from '../assets/ts/_dirname.js'; From 4edcda00bd3a0fc2d60911beec3b68a54b676285 Mon Sep 17 00:00:00 2001 From: MisterPapaye Date: Tue, 18 Nov 2025 20:49:35 +0100 Subject: [PATCH 02/11] mouve send to chatgpt + prepare project --- src/routes/api.ai.ts | 148 +-------------------------- src/routes/api.ai/send_to_chatgpt.ts | 148 +++++++++++++++++++++++++++ src/routes/api.ai/send_to_gemini.ts | 10 ++ src/routes/api.ai/types.ts | 9 ++ 4 files changed, 170 insertions(+), 145 deletions(-) create mode 100644 src/routes/api.ai/send_to_chatgpt.ts create mode 100644 src/routes/api.ai/send_to_gemini.ts create mode 100644 src/routes/api.ai/types.ts diff --git a/src/routes/api.ai.ts b/src/routes/api.ai.ts index a50b343..b05171e 100644 --- a/src/routes/api.ai.ts +++ b/src/routes/api.ai.ts @@ -1,7 +1,5 @@ import { UUID, randomUUID } from 'crypto'; import { Router, Request, Response, NextFunction } from 'express'; -import OpenAI from "openai"; -import { GoogleGenAI } from "@google/genai"; import fs from 'fs'; import path from 'path'; import __dirname from '../assets/ts/_dirname.js'; @@ -11,17 +9,11 @@ import db from '../assets/ts/database.js'; import notes_db from '../assets/ts/notes.js'; import tags_db from '../assets/ts/tags.js'; import { getMCPService } from '../mcp.js'; -import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions'; +import send_to_chatgpt from './api.ai/send_to_chatgpt.js'; +import { Chat } from './api.ai/types.js'; -const AIclient = new OpenAI({ apiKey: process.env.OPENAI_SECRET_KEY }); const router = Router(); -type Chat = { - uuid: UUID; - userID: string; - data: { notes: any; tags: any }; - messages: ChatCompletionMessageParam[]; -} let chats: Chat[] = []; @@ -102,141 +94,7 @@ router.post('/close', verify_auth, async (req: Request, res: Response) => { }); router.post('/send', verify_auth, async (req: Request, res: Response) => { - const { uuid, message } = req.body; - const note = req.body?.note || undefined; - - try { - const chat = chats.find(chat => chat.uuid == uuid); - - if (!chat) { - res.json({ error: true, message: 'Chat non trouvé' }); - return; - } - - // Préparer le prompt - let prompt: string = ''; - - if (!note) { - prompt = `Message de l'utilisateur : ${message}`; - } else { - let db_note = (await notes_db.getNoteByUUID(note)).note; - if (db_note) { - db_note = { ...db_note, content: db_note.content.replace(/]*>/g, '') }; - } - prompt = `Note ouverte : ${JSON.stringify({ db_note })}\n Message de l'utilisateur : ${message}`; - } - - chat.messages.push({ - role: 'user', - content: prompt - }); - - // Obtenir le service MCP - const mcpService = getMCPService(); - await mcpService.ensureConnected(); - - // Obtenir les outils MCP au format OpenAI - const mcpTools = mcpService.getOpenAITools(); - - // Configuration SSE - res.setHeader("Content-Type", "text/event-stream"); - res.setHeader("Cache-Control", "no-cache"); - res.setHeader("Connection", "keep-alive"); - res.flushHeaders(); - res.socket?.setNoDelay(true); - - let conversationMessages = [...chat.messages.slice(-10)]; - let iterationCount = 0; - const maxIterations = 5; - - // Boucle pour gérer les appels d'outils - while (iterationCount < maxIterations) { - iterationCount++; - - // Appel à OpenAI avec les outils MCP - const stream = await AIclient.chat.completions.create({ - model: "gpt-5-mini", - messages: conversationMessages, - tools: mcpTools.length > 0 ? mcpTools : undefined, - tool_choice: 'auto', - stream: true - }); - - let assistantMessage: string = ""; - let buffer: string = ''; - let toolCalls: any[] = []; - let currentToolCall: any = null; - - for await (const chunk of stream) { - const delta = chunk.choices[0]?.delta; - - // Gérer le contenu texte - if (delta?.content) { - const token = delta.content; - assistantMessage += token; - buffer += token; - res.write(`data: ${token}\n\n`); - } - - // Gérer les appels d'outils - if (delta?.tool_calls) { - for (const toolCallDelta of delta.tool_calls) { - if (toolCallDelta.index !== undefined) { - if (!toolCalls[toolCallDelta.index]) { - toolCalls[toolCallDelta.index] = { - id: toolCallDelta.id || '', - type: 'function', - function: { - name: toolCallDelta.function?.name || '', - arguments: '' - } - }; - } - - if (toolCallDelta.function?.arguments) { - toolCalls[toolCallDelta.index].function.arguments += toolCallDelta.function.arguments; - } - } - } - } - } - - // Ajouter le message de l'assistant - conversationMessages.push({ - role: 'assistant', - content: assistantMessage || null, - tool_calls: toolCalls.length > 0 ? toolCalls : undefined - } as any); - - chat.messages.push({ - role: 'assistant', - content: assistantMessage - }); - - // Si pas d'appel d'outil, on termine - if (toolCalls.length === 0) { - break; - } - - // Exécuter les appels d'outils via MCP - res.write(`data: [TOOLS:${toolCalls.map(tc => tc.function.name).join(',')}]\n\n`); - - const toolResults = await mcpService.handleToolCalls(toolCalls); - conversationMessages.push(...toolResults); - - // Envoyer les résultats au client - for (const result of toolResults) { - res.write(`data: [TOOL_RESULT:${result.content}]\n\n`); - } - } - - res.write("data: [DONE]\n\n"); - res.end(); - - } catch (err: any) { - console.error('Error in /send:', err); - res.status(500).json({ error: true, message: err.message }); - } + return send_to_chatgpt(req, res, chats); }); export default router; \ No newline at end of file diff --git a/src/routes/api.ai/send_to_chatgpt.ts b/src/routes/api.ai/send_to_chatgpt.ts new file mode 100644 index 0000000..636f583 --- /dev/null +++ b/src/routes/api.ai/send_to_chatgpt.ts @@ -0,0 +1,148 @@ +import type { Request, Response } from 'express'; +import OpenAI from "openai"; +import { Chat } from './types.js'; +import notes_db from '../../assets/ts/notes.js'; +import { getMCPService } from '../../mcp.js'; + +const AIclient = new OpenAI({ apiKey: process.env.OPENAI_SECRET_KEY }); + +export default async function send_to_chatgpt +(req: Request, res: Response, chats: Chat[]) +{ + + const { uuid, message } = req.body; + const note = req.body?.note || undefined; + + try { + const chat = chats.find(chat => chat.uuid == uuid); + + if (!chat) { + res.json({ error: true, message: 'Chat non trouvé' }); + return; + } + + // Préparer le prompt + let prompt: string = ''; + + if (!note) { + prompt = `Message de l'utilisateur : ${message}`; + } else { + let db_note = (await notes_db.getNoteByUUID(note)).note; + if (db_note) { + db_note = { ...db_note, content: db_note.content.replace(/]*>/g, '') }; + } + prompt = `Note ouverte : ${JSON.stringify({ db_note })}\n Message de l'utilisateur : ${message}`; + } + + chat.messages.push({ + role: 'user', + content: prompt + }); + + // Obtenir le service MCP + const mcpService = getMCPService(); + await mcpService.ensureConnected(); + + // Obtenir les outils MCP au format OpenAI + const mcpTools = mcpService.getOpenAITools(); + + // Configuration SSE + res.setHeader("Content-Type", "text/event-stream"); + res.setHeader("Cache-Control", "no-cache"); + res.setHeader("Connection", "keep-alive"); + res.flushHeaders(); + res.socket?.setNoDelay(true); + + let conversationMessages = [...chat.messages.slice(-10)]; + let iterationCount = 0; + const maxIterations = 5; + + // Boucle pour gérer les appels d'outils + while (iterationCount < maxIterations) { + iterationCount++; + + // Appel à OpenAI avec les outils MCP + const stream = await AIclient.chat.completions.create({ + model: "gpt-5-mini", + messages: conversationMessages, + tools: mcpTools.length > 0 ? mcpTools : undefined, + tool_choice: 'auto', + stream: true + }); + + let assistantMessage: string = ""; + let buffer: string = ''; + let toolCalls: any[] = []; + let currentToolCall: any = null; + + for await (const chunk of stream) { + const delta = chunk.choices[0]?.delta; + + // Gérer le contenu texte + if (delta?.content) { + const token = delta.content; + assistantMessage += token; + buffer += token; + res.write(`data: ${token}\n\n`); + } + + // Gérer les appels d'outils + if (delta?.tool_calls) { + for (const toolCallDelta of delta.tool_calls) { + if (toolCallDelta.index !== undefined) { + if (!toolCalls[toolCallDelta.index]) { + toolCalls[toolCallDelta.index] = { + id: toolCallDelta.id || '', + type: 'function', + function: { + name: toolCallDelta.function?.name || '', + arguments: '' + } + }; + } + + if (toolCallDelta.function?.arguments) { + toolCalls[toolCallDelta.index].function.arguments += toolCallDelta.function.arguments; + } + } + } + } + } + + // Ajouter le message de l'assistant + conversationMessages.push({ + role: 'assistant', + content: assistantMessage || null, + tool_calls: toolCalls.length > 0 ? toolCalls : undefined + } as any); + + chat.messages.push({ + role: 'assistant', + content: assistantMessage + }); + + // Si pas d'appel d'outil, on termine + if (toolCalls.length === 0) { + break; + } + + // Exécuter les appels d'outils via MCP + res.write(`data: [TOOLS:${toolCalls.map(tc => tc.function.name).join(',')}]\n\n`); + + const toolResults = await mcpService.handleToolCalls(toolCalls); + conversationMessages.push(...toolResults); + + // Envoyer les résultats au client + for (const result of toolResults) { + res.write(`data: [TOOL_RESULT:${result.content}]\n\n`); + } + } + + res.write("data: [DONE]\n\n"); + res.end(); + + } catch (err: any) { + console.error('Error in /send:', err); + res.status(500).json({ error: true, message: err.message }); + } +} \ No newline at end of file diff --git a/src/routes/api.ai/send_to_gemini.ts b/src/routes/api.ai/send_to_gemini.ts new file mode 100644 index 0000000..7bbd8b8 --- /dev/null +++ b/src/routes/api.ai/send_to_gemini.ts @@ -0,0 +1,10 @@ +import type { Request, Response } from 'express'; +import { GoogleGenAI } from "@google/genai"; + +const AIclient = new GoogleGenAI({}); + +export default async function send_to_gemini +(req: Request, res: Response) +{ + +} \ No newline at end of file diff --git a/src/routes/api.ai/types.ts b/src/routes/api.ai/types.ts new file mode 100644 index 0000000..69c1483 --- /dev/null +++ b/src/routes/api.ai/types.ts @@ -0,0 +1,9 @@ +import { UUID } from "crypto"; +import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions'; + +export interface Chat { + uuid: UUID; + userID: string; + data: { notes: any; tags: any }; + messages: ChatCompletionMessageParam[]; +} \ No newline at end of file From e2c8005a69fc4a0dd1e1873293f31e3776d9dcbe Mon Sep 17 00:00:00 2001 From: MisterPapaye Date: Tue, 18 Nov 2025 21:18:52 +0100 Subject: [PATCH 03/11] add first v of addaptation of ai function for gemini --- package-lock.json | 550 ++++++++++++++++++++++++++++ package.json | 2 + src/mcp.ts | 10 +- src/routes/api.ai/send_to_gemini.ts | 183 ++++++++- src/routes/api.ai/types.ts | 2 +- 5 files changed, 741 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 57a35d6..ebd12ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@clerk/clerk-sdk-node": "^4.13.23", "@clerk/express": "^1.7.13", "@google/genai": "^1.30.0", + "@google/generative-ai": "^0.24.1", "@modelcontextprotocol/sdk": "^1.20.2", "@tiptap/starter-kit": "^3.5.1", "@types/express": "^5.0.3", @@ -20,6 +21,7 @@ "crypto": "^1.0.1", "dotenv": "^16.5.0", "express": "^5.1.0", + "google": "^2.1.0", "jsdom": "^27.0.0", "jsonwebtoken": "^9.0.2", "lodash.isequal": "^4.5.0", @@ -1014,6 +1016,15 @@ } } }, + "node_modules/@google/generative-ai": { + "version": "0.24.1", + "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz", + "integrity": "sha512-MqO+MLfM6kjxcKoy0p1wRzG3b4ZZXtPI+z2IE26UogS2Cm/XHO+7gGRBh6gcJsOiIVoH93UwKvW4HdgiOZCy9Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1778,6 +1789,15 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "license": "Python-2.0" }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, "node_modules/asn1js": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.6.tgz", @@ -1792,12 +1812,30 @@ "node": ">=12.0.0" } }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, "node_modules/aws-ssl-profiles": { "version": "1.1.2", "license": "MIT", @@ -1805,6 +1843,12 @@ "node": ">= 6.0.0" } }, + "node_modules/aws4": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", + "license": "MIT" + }, "node_modules/balanced-match": { "version": "1.0.2", "license": "MIT" @@ -1852,6 +1896,15 @@ "version": "5.1.2", "license": "MIT" }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "license": "BSD-3-Clause", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, "node_modules/bidi-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", @@ -1898,6 +1951,12 @@ "node": ">=18" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, "node_modules/brace-expansion": { "version": "1.1.12", "license": "MIT", @@ -1990,10 +2049,38 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "license": "Apache-2.0" + }, "node_modules/change-case": { "version": "5.4.4", "license": "MIT" }, + "node_modules/cheerio": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.19.0.tgz", + "integrity": "sha512-Fwcm3zkR37STnPC8FepSHeSYJM5Rd596TZOcfDUdojR4Q735aK1Xn+M+ISagNneuCwMjK28w4kX+ETILGNT/UQ==", + "license": "MIT", + "dependencies": { + "css-select": "~1.0.0", + "dom-serializer": "~0.1.0", + "entities": "~1.1.1", + "htmlparser2": "~3.8.1", + "lodash": "^3.2.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cheerio/node_modules/entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "license": "BSD-2-Clause" + }, "node_modules/chokidar": { "version": "3.6.0", "license": "MIT", @@ -2096,6 +2183,12 @@ "node": ">=6.6.0" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, "node_modules/cors": { "version": "2.8.5", "license": "MIT", @@ -2131,6 +2224,18 @@ "version": "1.0.1", "license": "ISC" }, + "node_modules/css-select": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.0.0.tgz", + "integrity": "sha512-/xPlD7betkfd7ChGkLGGWx5HWyiHDOSn7aACLzdH0nwucPvB0EAm8hMBm7Xn7vGfAeRRN7KZ8wumGm8NoNcMRw==", + "license": "BSD-like", + "dependencies": { + "boolbase": "~1.0.0", + "css-what": "1.0", + "domutils": "1.4", + "nth-check": "~1.0.0" + } + }, "node_modules/css-tree": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", @@ -2144,6 +2249,15 @@ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, + "node_modules/css-what": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-1.0.0.tgz", + "integrity": "sha512-60SUMPBreXrLXgvpM8kYpO0AOyMRhdRlXFX5BMQbZq1SIJCyNE56nqFQhmvREQdUJpedbGRYZ5wOyq3/F6q5Zw==", + "license": "BSD-like", + "engines": { + "node": "*" + } + }, "node_modules/cssstyle": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.1.tgz", @@ -2162,6 +2276,18 @@ "version": "3.1.3", "license": "MIT" }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", @@ -2244,6 +2370,44 @@ "node": ">=6" } }, + "node_modules/dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "license": "MIT", + "dependencies": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "license": "BSD-2-Clause" + }, + "node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha512-q9bUwjfp7Eif8jWxxxPSykdRZAb6GkguBGSgvvCrhI9wB71W2K/Kvv4E61CF/mcCfnVJDeDWx/Vb/uAqbDj6UQ==", + "dependencies": { + "domelementtype": "1" + } + }, + "node_modules/domutils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.4.3.tgz", + "integrity": "sha512-ZkVgS/PpxjyJMb+S2iVHHEZjVnOUtjGp0/zstqKGTE9lrZtNHlNQmLwP/lhLMEApYbzc08BKMx9IFpKhaSbW1w==", + "dependencies": { + "domelementtype": "1" + } + }, "node_modules/dot-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", @@ -2282,6 +2446,16 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "license": "MIT" }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "license": "MIT", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "license": "Apache-2.0", @@ -2665,6 +2839,15 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ], + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2745,6 +2928,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, "node_modules/form-data": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", @@ -2905,6 +3097,15 @@ "node": ">= 0.4" } }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, "node_modules/glob": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", @@ -2963,6 +3164,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/google": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/google/-/google-2.1.0.tgz", + "integrity": "sha512-z1lOESyokyPB+nVIZ96LyW6Hw3u3AWSSQAZD0L9IrncRSCqCU12wOK6CH8AKsmZe6+6rSX+lJgIRq8LdRiVAUg==", + "license": "MIT", + "dependencies": { + "cheerio": "^0.19.0", + "request": "^2.54.0" + } + }, "node_modules/google-auth-library": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.5.0.tgz", @@ -3055,6 +3266,29 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "license": "MIT", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/has-flag": { "version": "3.0.0", "license": "MIT", @@ -3109,6 +3343,34 @@ "node": ">=18" } }, + "node_modules/htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha512-hBxEg3CYXe+rPIua8ETe7tmG3XDn9B0edOE/e9wH2nLczxzgdu0m0aNHY+5wFZiviLWLdANPJTssa92dMcXQ5Q==", + "license": "MIT", + "dependencies": { + "domelementtype": "1", + "domhandler": "2.3", + "domutils": "1.5", + "entities": "1.0", + "readable-stream": "1.1" + } + }, + "node_modules/htmlparser2/node_modules/domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ==", + "license": "BSD-like" + }, "node_modules/http-errors": { "version": "2.0.0", "license": "MIT", @@ -3136,6 +3398,21 @@ "node": ">= 14" } }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -3231,6 +3508,18 @@ "version": "1.0.2", "license": "MIT" }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "license": "MIT" + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3247,6 +3536,12 @@ "url": "https://github.com/sponsors/dmonad" } }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "license": "MIT" + }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", @@ -3276,6 +3571,12 @@ "license": "MIT", "peer": true }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "license": "MIT" + }, "node_modules/jsdom": { "version": "27.0.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.0.0.tgz", @@ -3324,12 +3625,24 @@ "bignumber.js": "^9.0.0" } }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "license": "MIT" }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC" + }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", @@ -3352,6 +3665,21 @@ "npm": ">=6" } }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "license": "MIT", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/jwa": { "version": "1.4.2", "license": "MIT", @@ -3405,6 +3733,12 @@ "integrity": "sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==", "license": "MIT" }, + "node_modules/lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ==", + "license": "MIT" + }, "node_modules/lodash.includes": { "version": "4.3.0", "license": "MIT" @@ -3801,6 +4135,24 @@ "node": ">=0.10.0" } }, + "node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "~1.0.0" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, "node_modules/object-assign": { "version": "4.1.1", "license": "MIT", @@ -3930,6 +4282,12 @@ "node": ">=16" } }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -4191,6 +4549,18 @@ "node": ">= 0.10" } }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, "node_modules/pstree.remy": { "version": "1.1.8", "license": "MIT" @@ -4286,6 +4656,18 @@ "node": ">=0.10.0" } }, + "node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, "node_modules/readdirp": { "version": "3.6.0", "license": "MIT", @@ -4296,6 +4678,95 @@ "node": ">=8.10.0" } }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "license": "Apache-2.0", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/request/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -4763,6 +5234,31 @@ "node": ">= 0.6" } }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "license": "MIT", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/standardwebhooks": { "version": "1.0.0", "license": "MIT", @@ -4782,6 +5278,12 @@ "version": "3.9.0", "license": "MIT" }, + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "license": "MIT" + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -5017,6 +5519,24 @@ "version": "2.8.1", "license": "0BSD" }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "license": "Unlicense" + }, "node_modules/type-fest": { "version": "4.41.0", "license": "(MIT OR CC0-1.0)", @@ -5087,6 +5607,16 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "license": "MIT", + "bin": { + "uuid": "bin/uuid" + } + }, "node_modules/vary": { "version": "1.1.2", "license": "MIT", @@ -5094,6 +5624,26 @@ "node": ">= 0.8" } }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "license": "MIT" + }, "node_modules/w3c-keyname": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", diff --git a/package.json b/package.json index ec21b58..f03771e 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@clerk/clerk-sdk-node": "^4.13.23", "@clerk/express": "^1.7.13", "@google/genai": "^1.30.0", + "@google/generative-ai": "^0.24.1", "@modelcontextprotocol/sdk": "^1.20.2", "@tiptap/starter-kit": "^3.5.1", "@types/express": "^5.0.3", @@ -28,6 +29,7 @@ "crypto": "^1.0.1", "dotenv": "^16.5.0", "express": "^5.1.0", + "google": "^2.1.0", "jsdom": "^27.0.0", "jsonwebtoken": "^9.0.2", "lodash.isequal": "^4.5.0", diff --git a/src/mcp.ts b/src/mcp.ts index e63c054..8d69c21 100644 --- a/src/mcp.ts +++ b/src/mcp.ts @@ -71,13 +71,21 @@ export class MCPService { console.log(`Loaded tools: ${this.tools.map(t => t.name).join(', ')}`); } - getOpenAITools() { + public getOpenAITools() { return this.openaiTools.map(tool => ({ ...tool, resources: ["note://*"], })); } + public getGeminiTools() { + return this.tools.map(tool => ({ + name: tool.function.name, + description: tool.function.description, + parameters: tool.function.parameters + })); + } + async callTool(name: string, args: any = {}) { if (!this.client) { throw new Error('MCP client not connected'); diff --git a/src/routes/api.ai/send_to_gemini.ts b/src/routes/api.ai/send_to_gemini.ts index 7bbd8b8..24ad5de 100644 --- a/src/routes/api.ai/send_to_gemini.ts +++ b/src/routes/api.ai/send_to_gemini.ts @@ -1,10 +1,185 @@ import type { Request, Response } from 'express'; -import { GoogleGenAI } from "@google/genai"; +import { GoogleGenerativeAI, Content } from '@google/generative-ai'; +import notes_db from '../../assets/ts/notes.js'; +import { getMCPService } from '../../mcp.js'; +import { UUID } from 'crypto'; -const AIclient = new GoogleGenAI({}); +export interface Chat { + uuid: UUID; + userID: string; + data: { notes: any; tags: any }; + messages: Content[]; +} + +const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY || ''); export default async function send_to_gemini -(req: Request, res: Response) +(req: Request, res: Response, chats: Chat[]) { - + + const { uuid, message } = req.body; + const note = req.body?.note || undefined; + + try { + const chat = chats.find(chat => chat.uuid == uuid); + + if (!chat) { + res.json({ error: true, message: 'Chat non trouvé' }); + return; + } + + // Préparer le prompt + let prompt: string = ''; + + if (!note) { + prompt = `Message de l'utilisateur : ${message}`; + } else { + let db_note = (await notes_db.getNoteByUUID(note)).note; + if (db_note) { + db_note = { ...db_note, content: db_note.content.replace(/]*>/g, '') }; + } + prompt = `Note ouverte : ${JSON.stringify({ db_note })}\n Message de l'utilisateur : ${message}`; + } + + chat.messages.push({ + role: 'user', + content: prompt + }); + + + const mcpService = getMCPService(); + await mcpService.ensureConnected(); + + // Obtenir les outils MCP au format Gemini + const mcpTools = mcpService.getGeminiTools(); + + // Configuration SSE + res.setHeader("Content-Type", "text/event-stream"); + res.setHeader("Cache-Control", "no-cache"); + res.setHeader("Connection", "keep-alive"); + res.flushHeaders(); + res.socket?.setNoDelay(true); + + // Convertir les messages au format Gemini + const convertToGeminiMessages = (messages: any[]): Content[] => { + return messages + .filter(msg => msg.role !== 'system') // Le system sera géré séparément + .map(msg => ({ + role: msg.role === 'assistant' ? 'model' : 'user', + parts: [{ text: msg.content || '' }] + })); + }; + + let conversationMessages = [...chat.messages.slice(-10)]; + let iterationCount = 0; + const maxIterations = 5; + + // Extraire le system message s'il existe + const systemMessage = conversationMessages.find(m => m.role === 'system'); + + // Boucle pour gérer les appels d'outils + while (iterationCount < maxIterations) { + iterationCount++; + + // Configurer le modèle Gemini + const model = genAI.getGenerativeModel({ + model: "gemini-2.5-pro", + systemInstruction: systemMessage?.content, + tools: mcpTools.length > 0 ? [{ + functionDeclarations: mcpTools + }] : undefined + }); + + // Convertir l'historique au format Gemini + const geminiHistory = convertToGeminiMessages(conversationMessages); + + // Démarrer le chat + const geminiChat = model.startChat({ + history: geminiHistory.slice(0, -1) // Tous sauf le dernier + }); + + // Envoyer le dernier message en streaming + const lastMessage = geminiHistory[geminiHistory.length - 1]; + const result = await geminiChat.sendMessageStream( + lastMessage.parts[0].text || '' + ); + + let assistantMessage: string = ""; + let buffer: string = ''; + let toolCalls: any[] = []; + + for await (const chunk of result.stream) { + const candidate = chunk.candidates?.[0]; + + if (!candidate) continue; + + // Gérer le contenu texte + if (candidate.content?.parts) { + for (const part of candidate.content.parts) { + if (part.text) { + const token = part.text; + assistantMessage += token; + buffer += token; + res.write(`data: ${token}\n\n`); + } + + // Gérer les appels d'outils + if (part.functionCall) { + const toolCall = { + id: `call_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, + type: 'function' as const, + function: { + name: part.functionCall.name, + arguments: JSON.stringify(part.functionCall.args) + } + }; + + toolCalls.push(toolCall); + } + } + } + } + + // Ajouter le message de l'assistant + conversationMessages.push({ + role: 'assistant', + content: assistantMessage || null, + tool_calls: toolCalls.length > 0 ? toolCalls : undefined + } as any); + + chat.messages.push({ + role: 'assistant', + content: assistantMessage + }); + + // Si pas d'appel d'outil, on termine + if (toolCalls.length === 0) { + break; + } + + // Exécuter les appels d'outils via MCP + res.write(`data: [TOOLS:${toolCalls.map(tc => tc.function.name).join(',')}]\n\n`); + + const toolResults = await mcpService.handleToolCalls(toolCalls); + + // Convertir les résultats au format compatible + for (const result of toolResults) { + conversationMessages.push({ + role: 'function', + name: result.tool_call_id, + content: result.content + }); + + res.write(`data: [TOOL_RESULT:${result.content}]\n\n`); + } + } + + res.write("data: [DONE]\n\n"); + res.end(); + + } catch (err: any) { + console.error('Error in /send:', err); + res.status(500).json({ error: true, message: err.message }); + } + } \ No newline at end of file diff --git a/src/routes/api.ai/types.ts b/src/routes/api.ai/types.ts index 69c1483..c00e824 100644 --- a/src/routes/api.ai/types.ts +++ b/src/routes/api.ai/types.ts @@ -6,4 +6,4 @@ export interface Chat { userID: string; data: { notes: any; tags: any }; messages: ChatCompletionMessageParam[]; -} \ No newline at end of file +} From d9c31dfe9f7ef70f7cafa4dc653402f4dbbc6480 Mon Sep 17 00:00:00 2001 From: MisterPapaye Date: Tue, 18 Nov 2025 21:21:49 +0100 Subject: [PATCH 04/11] update google generative ai func --- src/routes/api.ai/send_to_gemini.ts | 40 +++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/routes/api.ai/send_to_gemini.ts b/src/routes/api.ai/send_to_gemini.ts index 24ad5de..d3dcf94 100644 --- a/src/routes/api.ai/send_to_gemini.ts +++ b/src/routes/api.ai/send_to_gemini.ts @@ -63,11 +63,41 @@ export default async function send_to_gemini // Convertir les messages au format Gemini const convertToGeminiMessages = (messages: any[]): Content[] => { return messages - .filter(msg => msg.role !== 'system') // Le system sera géré séparément - .map(msg => ({ - role: msg.role === 'assistant' ? 'model' : 'user', - parts: [{ text: msg.content || '' }] - })); + .filter(msg => msg.role !== 'system') + .map(msg => { + const parts: Part[] = []; + + if (msg.content) { + parts.push({ text: msg.content }); + } + + if (msg.tool_calls && msg.tool_calls.length > 0) { + for (const toolCall of msg.tool_calls) { + parts.push({ + functionCall: { + name: toolCall.function.name, + args: JSON.parse(toolCall.function.arguments) + } + }); + } + } + + if (msg.role === 'function') { + parts.push({ + functionResponse: { + name: msg.name, + response: { + content: msg.content + } + } + }); + } + + return { + role: msg.role === 'assistant' || msg.role === 'function' ? 'model' : 'user', + parts + } as Content; + }); }; let conversationMessages = [...chat.messages.slice(-10)]; From 10e9b8a4ec35788d1d78826001c63ac7d2ae5dee Mon Sep 17 00:00:00 2001 From: MisterPapaye Date: Tue, 18 Nov 2025 21:21:53 +0100 Subject: [PATCH 05/11] fix --- src/routes/api.ai/send_to_gemini.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/api.ai/send_to_gemini.ts b/src/routes/api.ai/send_to_gemini.ts index d3dcf94..fc76563 100644 --- a/src/routes/api.ai/send_to_gemini.ts +++ b/src/routes/api.ai/send_to_gemini.ts @@ -1,5 +1,5 @@ import type { Request, Response } from 'express'; -import { GoogleGenerativeAI, Content } from '@google/generative-ai'; +import { GoogleGenerativeAI, Content, Part } from '@google/generative-ai'; import notes_db from '../../assets/ts/notes.js'; import { getMCPService } from '../../mcp.js'; import { UUID } from 'crypto'; @@ -8,7 +8,7 @@ export interface Chat { uuid: UUID; userID: string; data: { notes: any; tags: any }; - messages: Content[]; + messages: { content: string, role: string }[]; } const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY || ''); @@ -196,7 +196,7 @@ export default async function send_to_gemini for (const result of toolResults) { conversationMessages.push({ role: 'function', - name: result.tool_call_id, + //name: result.tool_call_id, content: result.content }); From 0a57099cb89f01816e56691a73b328e086a86b96 Mon Sep 17 00:00:00 2001 From: MisterPapaye Date: Tue, 18 Nov 2025 21:37:08 +0100 Subject: [PATCH 06/11] fix mcp tools --- src/mcp.ts | 60 ++++++++++++++++++++++++++--- src/routes/api.ai.ts | 6 ++- src/routes/api.ai/send_to_gemini.ts | 8 +++- 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/src/mcp.ts b/src/mcp.ts index 8d69c21..65ff48d 100644 --- a/src/mcp.ts +++ b/src/mcp.ts @@ -78,12 +78,60 @@ export class MCPService { })); } - public getGeminiTools() { - return this.tools.map(tool => ({ - name: tool.function.name, - description: tool.function.description, - parameters: tool.function.parameters - })); + public getGeminiTools() + { + if (!this.tools || this.tools.length === 0) { + return []; + } + + return this.tools + .filter(tool => tool && (tool.function?.name || tool.name)) + .map(tool => { + const isOpenAIFormat = 'function' in tool; + + const parameters = isOpenAIFormat + ? tool.function.parameters + : (tool.inputSchema || tool.parameters || {}); + + const cleanedParameters = this.cleanSchemaForGemini(parameters); + + return { + name: isOpenAIFormat ? tool.function.name : tool.name, + description: isOpenAIFormat ? tool.function.description : tool.description, + parameters: cleanedParameters + }; + }); + } + + private cleanSchemaForGemini(schema: any): any + { + if (!schema || typeof schema !== 'object') { + return schema; + } + + const cleaned = JSON.parse(JSON.stringify(schema)); + + const removeInvalidFields = (obj: any): any => { + if (Array.isArray(obj)) { + return obj.map(removeInvalidFields); + } + + if (obj && typeof obj === 'object') { + + delete obj.$schema; + delete obj.additionalProperties; + delete obj.$defs; + delete obj.definitions; + + for (const key in obj) { + obj[key] = removeInvalidFields(obj[key]); + } + } + + return obj; + }; + + return removeInvalidFields(cleaned); } async callTool(name: string, args: any = {}) { diff --git a/src/routes/api.ai.ts b/src/routes/api.ai.ts index b05171e..3bd07d6 100644 --- a/src/routes/api.ai.ts +++ b/src/routes/api.ai.ts @@ -11,11 +11,12 @@ import tags_db from '../assets/ts/tags.js'; import { getMCPService } from '../mcp.js'; import send_to_chatgpt from './api.ai/send_to_chatgpt.js'; import { Chat } from './api.ai/types.js'; +import send_to_gemini from './api.ai/send_to_gemini.js'; const router = Router(); -let chats: Chat[] = []; +let chats: any[] = []; function verify_auth(req: Request, res: Response, next: NextFunction) { next(); @@ -94,7 +95,8 @@ router.post('/close', verify_auth, async (req: Request, res: Response) => { }); router.post('/send', verify_auth, async (req: Request, res: Response) => { - return send_to_chatgpt(req, res, chats); + //send_to_chatgpt(req, res, chats); + send_to_gemini(req, res, chats); }); export default router; \ No newline at end of file diff --git a/src/routes/api.ai/send_to_gemini.ts b/src/routes/api.ai/send_to_gemini.ts index fc76563..10b2539 100644 --- a/src/routes/api.ai/send_to_gemini.ts +++ b/src/routes/api.ai/send_to_gemini.ts @@ -209,7 +209,13 @@ export default async function send_to_gemini } catch (err: any) { console.error('Error in /send:', err); - res.status(500).json({ error: true, message: err.message }); + + if (!res.headersSent) { + res.status(500).json({ error: true, message: err.message }); + } else { + res.write(`data: [ERROR]${err.message}\n\n`); + res.end(); + } } } \ No newline at end of file From 2b9f6eefd7af6b6c076ec25ca944f05bdee0984d Mon Sep 17 00:00:00 2001 From: MisterPapaye Date: Tue, 18 Nov 2025 21:44:27 +0100 Subject: [PATCH 07/11] fix tools use ? idk --- src/routes/api.ai/send_to_gemini.ts | 31 ++++++++++++++++------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/routes/api.ai/send_to_gemini.ts b/src/routes/api.ai/send_to_gemini.ts index 10b2539..2ec27c4 100644 --- a/src/routes/api.ai/send_to_gemini.ts +++ b/src/routes/api.ai/send_to_gemini.ts @@ -67,6 +67,20 @@ export default async function send_to_gemini .map(msg => { const parts: Part[] = []; + if (msg.role === 'function') { + return { + role: 'user', + parts: [{ + functionResponse: { + name: msg.name, + response: { + content: msg.content + } + } + }] + } as Content; + } + if (msg.content) { parts.push({ text: msg.content }); } @@ -82,19 +96,8 @@ export default async function send_to_gemini } } - if (msg.role === 'function') { - parts.push({ - functionResponse: { - name: msg.name, - response: { - content: msg.content - } - } - }); - } - return { - role: msg.role === 'assistant' || msg.role === 'function' ? 'model' : 'user', + role: msg.role === 'assistant' ? 'model' : 'user', parts } as Content; }); @@ -172,13 +175,13 @@ export default async function send_to_gemini // Ajouter le message de l'assistant conversationMessages.push({ - role: 'assistant', + role: 'function', content: assistantMessage || null, tool_calls: toolCalls.length > 0 ? toolCalls : undefined } as any); chat.messages.push({ - role: 'assistant', + role: 'function', content: assistantMessage }); From 96ccdff289f9d2e5ba64831d37195bcb90f8a6c9 Mon Sep 17 00:00:00 2001 From: MisterPapaye Date: Fri, 21 Nov 2025 22:42:21 +0100 Subject: [PATCH 08/11] Update ws.ts --- src/ws.ts | 95 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/src/ws.ts b/src/ws.ts index b8c704b..183a76c 100644 --- a/src/ws.ts +++ b/src/ws.ts @@ -45,14 +45,18 @@ io.on("connection", (socket) => { console.log("Client connected :", socket.id); socket.on("join-room", async ({ room, userId }: { room: string, userId?: string }) => { + if (!room) return; socket.join(room); let docData = docs.get(room); if (!docData) { + const ydoc = new Y.Doc(); - new Y.Text(); + + // TipTap stocke le contenu ProseMirror dans un XmlFragment (pas utiliser de ytext) + const fragment = ydoc.getXmlFragment("prosemirror"); const awareness = new awarenessProtocol.Awareness(ydoc); const note = await get_note(room); @@ -60,6 +64,9 @@ io.on("connection", (socket) => { const title = note?.title || ""; const icon = note?.icon || ""; + // Ne pas initialiser le contenu manuellement + // il sera géré par TipTap côté client + const saveNote = async () => { const currentDoc = docs.get(room); const currentNote = await get_note(room); @@ -83,59 +90,86 @@ io.on("connection", (socket) => { const { ydoc, awareness } = docData; - // Envoi de l'état complet const initialState = Y.encodeStateAsUpdate(ydoc); - socket.emit("sync", initialState); + + const stateArray = Array.from(initialState); + socket.emit("sync", stateArray); + + socket.emit("title-update", docData.title); + socket.emit("icon-update", docData.icon); + if (userId) { socket.emit('new_user', userId); } - socket.on("y-update", async (update: Uint8Array) => { + socket.on("y-update", async (update: Uint8Array | number[]) => + { + try { - - const uint8Array = new Uint8Array(update); + + const uint8Array = update instanceof Uint8Array + ? update + : new Uint8Array(update); + Y.applyUpdate(ydoc, uint8Array); - socket.to(room).emit("y-update", uint8Array); - + socket.to(room).emit("y-update", Array.from(uint8Array)); + } catch (error) { console.error("Error applying update:", error); } + }); - socket.on('title-update', async (update: string) => { + socket.on('title-update', async (update: string) => + { + try { + const currentDoc = docs.get(room); - if (currentDoc) { + + if (currentDoc) + { currentDoc.title = update; socket.to(room).emit("title-update", update); - console.log('title update : ', update) } + } catch (error) { console.error("Error applying update:", error); } + }); - socket.on('icon-update', async (update: string) => { + socket.on('icon-update', async (update: string) => + { + try { + const currentDoc = docs.get(room); - if (currentDoc) { + + if (currentDoc) + { currentDoc.icon = update; socket.to(room).emit("icon-update", update); } + } catch (error) { console.error("Error applying update:", error); } + }) - socket.on("awareness-update", (update: Uint8Array) => { + socket.on("awareness-update", (update: Uint8Array | number[]) => + { try { - const uint8Array = new Uint8Array(update); + const uint8Array = update instanceof Uint8Array + ? update + : new Uint8Array(update); awarenessProtocol.applyAwarenessUpdate(awareness, uint8Array, socket); - socket.to(room).emit("awareness-update", uint8Array); + socket.to(room).emit("awareness-update", Array.from(uint8Array)); } catch (error) { console.error("Error applying awareness update:", error); @@ -143,16 +177,21 @@ io.on("connection", (socket) => { }); - socket.on('ai-command', async (data: { command: string; content: any }) => { + socket.on('ai-command', async (data: { command: string; content: any }) => + { + console.log(`AI command received in room ${room}:`, data.command); try { + if (data.command === 'insertContent') { io.to(room).emit('ai-command', data); } + } catch (error) { console.error("Error handling AI command:", error); } + }); socket.on("disconnect", async () => { @@ -164,13 +203,19 @@ io.on("connection", (socket) => { if (!docData) return; const { ydoc, saveInterval } = docData; - const content = ydoc.getText("prosemirror").toString(); + + // info de claude pour passer autosave dans back // + + // Pour sauvegarder en HTML, vous devrez utiliser une librairie + // comme prosemirror-model pour convertir le XmlFragment en HTML + // Pour l'instant, on sauvegarde juste les métadonnées + // Le contenu sera sauvegardé via l'autosave périodique côté client const note: Note | undefined = await get_note(roomId); if (note) { await save_note({ ...note, - content, + // contenu maj avec autosave du client title: docData.title, icon: docData.icon }); @@ -179,7 +224,6 @@ io.on("connection", (socket) => { awareness.setLocalState(null); if (room && io.sockets.adapter.rooms.get(room)?.size === 0) { - // Clear the save interval when the last user leaves if (saveInterval) { clearInterval(saveInterval); } @@ -187,21 +231,12 @@ io.on("connection", (socket) => { } console.log("Client disconnected:", socket.id); - }); - - }); - - }); - - console.log("Socket.IO server running..."); - -// Démarrage serveur httpServer.listen('3434', () => { console.log(`Serveur WebSocket sur le port 3434`); -}); +}); \ No newline at end of file From d856b142e39df10ac43920dde95d905f55eb554f Mon Sep 17 00:00:00 2001 From: MisterPapaye Date: Mon, 24 Nov 2025 19:01:06 +0100 Subject: [PATCH 09/11] fix and update ai --- src/mcp.ts | 28 ++++++++++++++++++++++++ src/routes/api.ai.ts | 14 ++++++++++-- src/routes/api.ai/send_to_gemini.ts | 34 ++++++++++++++--------------- src/routes/api.ts | 2 +- 4 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/mcp.ts b/src/mcp.ts index 65ff48d..7d8fc92 100644 --- a/src/mcp.ts +++ b/src/mcp.ts @@ -160,6 +160,34 @@ export class MCPService { } } + async handleToolCallsGemini(toolCalls: any[]) { + const results = []; + + for (const toolCall of toolCalls) { + const name = toolCall.function.name; + const args = JSON.parse(toolCall.function.arguments); + + try { + const result = await this.callTool(name, args); + + results.push({ + role: 'function', + name: name, + content: result + }); + + } catch (error: any) { + results.push({ + role: 'function', + name: name, + content: `Error: ${error.message}` + }); + } + } + + return results; + } + async handleToolCalls(toolCalls: OpenAI.Chat.Completions.ChatCompletionMessageToolCall[]) { const results = []; diff --git a/src/routes/api.ai.ts b/src/routes/api.ai.ts index 3bd07d6..bf8f92b 100644 --- a/src/routes/api.ai.ts +++ b/src/routes/api.ai.ts @@ -95,8 +95,18 @@ router.post('/close', verify_auth, async (req: Request, res: Response) => { }); router.post('/send', verify_auth, async (req: Request, res: Response) => { - //send_to_chatgpt(req, res, chats); - send_to_gemini(req, res, chats); + + const model = req.query?.model as 'gpt' | 'gemini'; + + if (true || model && model == 'gpt') + { + send_to_chatgpt(req, res, chats); + } + else + { + send_to_gemini(req, res, chats); + } + }); export default router; \ No newline at end of file diff --git a/src/routes/api.ai/send_to_gemini.ts b/src/routes/api.ai/send_to_gemini.ts index 2ec27c4..a6a412d 100644 --- a/src/routes/api.ai/send_to_gemini.ts +++ b/src/routes/api.ai/send_to_gemini.ts @@ -69,32 +69,30 @@ export default async function send_to_gemini if (msg.role === 'function') { return { - role: 'user', + role: 'function', parts: [{ functionResponse: { - name: msg.name, - response: { - content: msg.content - } + name: msg.name || 'unknown_tool', + response: { content: msg.content } } }] } as Content; } - + if (msg.content) { parts.push({ text: msg.content }); } - if (msg.tool_calls && msg.tool_calls.length > 0) { - for (const toolCall of msg.tool_calls) { - parts.push({ - functionCall: { - name: toolCall.function.name, - args: JSON.parse(toolCall.function.arguments) - } - }); - } - } + // if (msg.tool_calls && msg.tool_calls.length > 0) { + // for (const toolCall of msg.tool_calls) { + // parts.push({ + // functionCall: { + // name: toolCall.function.name, + // args: JSON.parse(toolCall.function.arguments) + // } + // }); + // } + // } return { role: msg.role === 'assistant' ? 'model' : 'user', @@ -193,13 +191,13 @@ export default async function send_to_gemini // Exécuter les appels d'outils via MCP res.write(`data: [TOOLS:${toolCalls.map(tc => tc.function.name).join(',')}]\n\n`); - const toolResults = await mcpService.handleToolCalls(toolCalls); + const toolResults = await mcpService.handleToolCallsGemini(toolCalls); // Convertir les résultats au format compatible for (const result of toolResults) { conversationMessages.push({ role: 'function', - //name: result.tool_call_id, + //name: result.name, content: result.content }); diff --git a/src/routes/api.ts b/src/routes/api.ts index c757ba3..3890029 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -13,7 +13,7 @@ const router = Router(); router.get('/get_news', async (req: Request, res: Response) => { - const data = await fs.promises.readFile('./config.json', 'utf-8'); + const data = await fs.promises.readFile('./dist/config.json', 'utf-8'); // remettre ./config pour prod const news: Promise = JSON.parse(data).news; res.json( (await news).active ? news : false ); From 0705994f9760009ad8b732c7b051d0d00a309409 Mon Sep 17 00:00:00 2001 From: MisterPapaye Date: Mon, 24 Nov 2025 19:08:31 +0100 Subject: [PATCH 10/11] remove ws autosave --- src/ws.ts | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/ws.ts b/src/ws.ts index 183a76c..c33c620 100644 --- a/src/ws.ts +++ b/src/ws.ts @@ -67,21 +67,23 @@ io.on("connection", (socket) => { // Ne pas initialiser le contenu manuellement // il sera géré par TipTap côté client - const saveNote = async () => { - const currentDoc = docs.get(room); - const currentNote = await get_note(room); - if (currentNote && currentDoc) { - await save_note({ - ...currentNote, - title: currentDoc.title, - icon: currentDoc.icon - }); - } - } - - await saveNote(); + // const saveNote = async () => { + // const currentDoc = docs.get(room); + // const currentNote = await get_note(room); + // if (currentNote && currentDoc) { + // await save_note({ + // ...currentNote, + // title: currentDoc.title, + // icon: currentDoc.icon + // }); + // } + // } + // await saveNote(); + const saveInterval = setInterval(async () => { - await saveNote(); + // auto save gérer par le client !!! + clearInterval(saveInterval); + //await saveNote(); }, 10000); docs.set(room, { ydoc, awareness, saveInterval, title, icon }); From c43a1cc78bff777a351d6464c44d36dd6ffd3901 Mon Sep 17 00:00:00 2001 From: MisterPapaye Date: Fri, 28 Nov 2025 13:18:31 +0100 Subject: [PATCH 11/11] update silverai --- src/assets/config/jeremy_ai.json | 2 +- src/routes/api.ai/send_to_chatgpt.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/assets/config/jeremy_ai.json b/src/assets/config/jeremy_ai.json index da62d77..6a8bdd6 100644 --- a/src/assets/config/jeremy_ai.json +++ b/src/assets/config/jeremy_ai.json @@ -1,3 +1,3 @@ { - "prompt_system": "Tu dois ecrir au format MarkDown en html. Pour faire des todolist tu dois faire une list sous ce format d'example :
  • dsq

. Pour integrer un saut de ligne, met ce code décolé avec un espace : '#34'. Pour le markdown, les fonction comme **text** et __text__ doivent être colé au text. Tu es le chatbot de l'application de prise de notes 'silvernote', tu te nommes 'SilverIA'. Tu parles par default français. Ton rôle est d'aider l'utilisateur à organiser ses notes, gerer ses dossiers, répondre aux questions sur l'application et donner des conseils pour mieux gérer ses notes. Tu dois être toujours poli, clair et encourageant. Tu dois repondre avec des reponse breve. Tu ne peux pas inventer d'informations sur l'utilisateur en dehors de ce qu'il te fournit. Si une question est hors sujet ou que tu ne sais pas, tu dois le dire poliment. Les notes et tag de cet utilisateur te seront fournit a chaque message. Ne dit pas de truc inutile dans tes reponses. L'utilisateur sait qui tu est sauf si il te le demande. Tu peut effectué des acction pour agir sur les notes et dossier/tag de l'utilisateur." + "prompt_system": "Tu dois ecrir au format MarkDown en html. Pour faire des todolist tu dois faire une list sous ce format d'example :
  • dsq

. Pour le markdown, les fonction comme **text** et __text__ doivent être colé au text. Tu es le chatbot de l'application de prise de notes 'silvernote'. Tu parles par default en français. Ton rôle est d'aider l'utilisateur à organiser ses notes, gerer ses dossiers, répondre aux questions sur l'application et donner des conseils pour mieux gérer ses notes. Tu dois être toujours poli, clair et encourageant. Tu dois repondre avec des reponse breve. Tu ne peux pas inventer d'informations sur l'utilisateur en dehors de ce qu'il te fournit. Si une question est hors sujet ou que tu ne sais pas, tu dois le dire poliment. Les notes et tag de cet utilisateur te seront fournit a chaque message. Ne dit pas de truc inutile dans tes reponses. L'utilisateur sait qui tu est sauf si il te le demande. Tu peut effectué des acction pour agir sur les notes et dossier/tag de l'utilisateur." } diff --git a/src/routes/api.ai/send_to_chatgpt.ts b/src/routes/api.ai/send_to_chatgpt.ts index 636f583..da580a1 100644 --- a/src/routes/api.ai/send_to_chatgpt.ts +++ b/src/routes/api.ai/send_to_chatgpt.ts @@ -63,7 +63,7 @@ export default async function send_to_chatgpt // Appel à OpenAI avec les outils MCP const stream = await AIclient.chat.completions.create({ - model: "gpt-5-mini", + model: "gpt-5.1", messages: conversationMessages, tools: mcpTools.length > 0 ? mcpTools : undefined, tool_choice: 'auto',