diff --git a/Dockerfile b/Dockerfile index 6386189..9ef0693 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,17 +15,5 @@ COPY src ./src COPY scripts ./scripts RUN npx tsc -# Permissions for dist directory, -# so config.ts can be compiled there during runtime -# regardless of the user of the container -RUN chmod 777 dist - -# Create a db directory for sqlite database file -# it is required because in order to write to sqlite file -# the directory must be writable -RUN mkdir /db -RUN chmod 777 /db - # Run the app CMD ["node", "dist/src/index.js"] -STOPSIGNAL SIGINT diff --git a/package-lock.json b/package-lock.json index ec40cc9..f35449d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,22 +9,21 @@ "version": "0.1.0", "license": "MIT", "dependencies": { - "@prisma/client": "5.13.0", - "discord.js": "14.14.1", + "@prisma/client": "5.7.0", + "discord.js": "^14.8.0", "fold-to-ascii": "^5.0.1", "gpt-3-encoder": "^1.1.4", - "openai": "^4.38.3", + "openai": "^4.10.0", "require-directory": "^2.1.1", - "typescript": "^5.4.5" + "typescript": "^5.1.6" }, "devDependencies": { "@types/fold-to-ascii": "^5.0.0", "@types/require-directory": "^2.1.2", - "@typescript-eslint/eslint-plugin": "^7.7.1", - "@typescript-eslint/parser": "^7.7.1", - "eslint": "^8.57.0", - "json-schema-to-ts": "^3.0.1", - "prisma": "5.13.0" + "@typescript-eslint/eslint-plugin": "^6.2.0", + "@typescript-eslint/parser": "^6.2.0", + "eslint": "^8.46.0", + "prisma": "5.7.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -36,18 +35,6 @@ "node": ">=0.10.0" } }, - "node_modules/@babel/runtime": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", - "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@discordjs/builders": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.7.0.tgz", @@ -193,81 +180,37 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", + "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", + "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", "engines": { "node": ">=14" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -282,9 +225,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, "node_modules/@nodelib/fs.scandir": { @@ -323,9 +266,9 @@ } }, "node_modules/@prisma/client": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.13.0.tgz", - "integrity": "sha512-uYdfpPncbZ/syJyiYBwGZS8Gt1PTNoErNYMuqHDa2r30rNSFtgTA/LXsSk55R7pdRTMi5pHkeP9B14K6nHmwkg==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.7.0.tgz", + "integrity": "sha512-cZmglCrfNbYpzUtz7HscVHl38e9CrUs31nrVoGUK1nIPXGgt8hT4jj2s657UXcNdQ/jBUxDgGmHyu2Nyrq1txg==", "hasInstallScript": true, "engines": { "node": ">=16.13" @@ -340,69 +283,70 @@ } }, "node_modules/@prisma/debug": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.13.0.tgz", - "integrity": "sha512-699iqlEvzyCj9ETrXhs8o8wQc/eVW+FigSsHpiskSFydhjVuwTJEfj/nIYqTaWFYuxiWQRfm3r01meuW97SZaQ==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.7.0.tgz", + "integrity": "sha512-tZ+MOjWlVvz1kOEhNYMa4QUGURY+kgOUBqLHYIV8jmCsMuvA1tWcn7qtIMLzYWCbDcQT4ZS8xDgK0R2gl6/0wA==", "devOptional": true }, "node_modules/@prisma/engines": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.13.0.tgz", - "integrity": "sha512-hIFLm4H1boj6CBZx55P4xKby9jgDTeDG0Jj3iXtwaaHmlD5JmiDkZhh8+DYWkTGchu+rRF36AVROLnk0oaqhHw==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.7.0.tgz", + "integrity": "sha512-TkOMgMm60n5YgEKPn9erIvFX2/QuWnl3GBo6yTRyZKk5O5KQertXiNnrYgSLy0SpsKmhovEPQb+D4l0SzyE7XA==", "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/debug": "5.13.0", - "@prisma/engines-version": "5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b", - "@prisma/fetch-engine": "5.13.0", - "@prisma/get-platform": "5.13.0" + "@prisma/debug": "5.7.0", + "@prisma/engines-version": "5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9", + "@prisma/fetch-engine": "5.7.0", + "@prisma/get-platform": "5.7.0" } }, "node_modules/@prisma/engines-version": { - "version": "5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b.tgz", - "integrity": "sha512-AyUuhahTINGn8auyqYdmxsN+qn0mw3eg+uhkp8zwknXYIqoT3bChG4RqNY/nfDkPvzWAPBa9mrDyBeOnWSgO6A==", + "version": "5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9.tgz", + "integrity": "sha512-V6tgRVi62jRwTm0Hglky3Scwjr/AKFBFtS+MdbsBr7UOuiu1TKLPc6xfPiyEN1+bYqjEtjxwGsHgahcJsd1rNg==", "devOptional": true }, "node_modules/@prisma/fetch-engine": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.13.0.tgz", - "integrity": "sha512-Yh4W+t6YKyqgcSEB3odBXt7QyVSm0OQlBSldQF2SNXtmOgMX8D7PF/fvH6E6qBCpjB/yeJLy/FfwfFijoHI6sA==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.7.0.tgz", + "integrity": "sha512-zIn/qmO+N/3FYe7/L9o+yZseIU8ivh4NdPKSkQRIHfg2QVTVMnbhGoTcecbxfVubeTp+DjcbjS0H9fCuM4W04w==", "devOptional": true, "dependencies": { - "@prisma/debug": "5.13.0", - "@prisma/engines-version": "5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b", - "@prisma/get-platform": "5.13.0" + "@prisma/debug": "5.7.0", + "@prisma/engines-version": "5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9", + "@prisma/get-platform": "5.7.0" } }, "node_modules/@prisma/get-platform": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.13.0.tgz", - "integrity": "sha512-B/WrQwYTzwr7qCLifQzYOmQhZcFmIFhR81xC45gweInSUn2hTEbfKUPd2keAog+y5WI5xLAFNJ3wkXplvSVkSw==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.7.0.tgz", + "integrity": "sha512-ZeV/Op4bZsWXuw5Tg05WwRI8BlKiRFhsixPcAM+5BKYSiUZiMKIi713tfT3drBq8+T0E1arNZgYSA9QYcglWNA==", "devOptional": true, "dependencies": { - "@prisma/debug": "5.13.0" + "@prisma/debug": "5.7.0" } }, "node_modules/@sapphire/async-queue": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.2.tgz", - "integrity": "sha512-7X7FFAA4DngXUl95+hYbUF19bp1LGiffjJtu7ygrZrbdCSsdDDBaSjB7Akw0ZbOu6k0xpXyljnJ6/RZUvLfRdg==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.1.tgz", + "integrity": "sha512-1RdpsmDQR/aWfp8oJzPtn4dNQrbpqSL5PIA0uAB/XwerPXUf994Ug1au1e7uGcD7ei8/F63UDjr5GWps1g/HxQ==", "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" } }, "node_modules/@sapphire/shapeshift": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.7.tgz", - "integrity": "sha512-4It2mxPSr4OGn4HSQWGmhFMsNFGfFVhWeRPCRwbH972Ek2pzfGRZtb0pJ4Ze6oIzcyh2jw7nUDa6qGlWofgd9g==", + "version": "3.9.4", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.4.tgz", + "integrity": "sha512-SiOoCBmm8O7QuadLJnX4V0tAkhC54NIOZJtmvw+5zwnHaiulGkjY02wxCuK8Gf4V540ILmGz+UulC0U8mrOZjg==", "dependencies": { "fast-deep-equal": "^3.1.3", "lodash": "^4.17.21" }, "engines": { - "node": ">=v16" + "node": ">=v14.0.0", + "npm": ">=7.0.0" } }, "node_modules/@sapphire/snowflake": { @@ -427,17 +371,17 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", - "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "version": "20.10.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz", + "integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==", "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@types/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-bQVlnMLFJ2d35DkPNjEPmd9ueO/rh5EiaZt2bhqiSarPjZIuIV6bPQVqcrEyvNo+AfTrRGVazle1tl597w3gfA==", "dependencies": { "@types/node": "*", "form-data": "^4.0.0" @@ -453,9 +397,9 @@ } }, "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, "node_modules/@types/ws": { @@ -467,33 +411,33 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz", - "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.14.0.tgz", + "integrity": "sha512-1ZJBykBCXaSHG94vMMKmiHoL0MhNHKSVlcHVYZNw+BKxufhqQVTOawNpwwI1P5nIFZ/4jLVop0mcY6mJJDFNaw==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/type-utils": "7.7.1", - "@typescript-eslint/utils": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.14.0", + "@typescript-eslint/type-utils": "6.14.0", + "@typescript-eslint/utils": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0", "debug": "^4.3.4", "graphemer": "^1.4.0", - "ignore": "^5.3.1", + "ignore": "^5.2.4", "natural-compare": "^1.4.0", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -502,26 +446,26 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz", - "integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.14.0.tgz", + "integrity": "sha512-QjToC14CKacd4Pa7JK4GeB/vHmWFJckec49FR4hmIRf97+KXole0T97xxu9IFiPxVQ1DBWrQ5wreLwAGwWAVQA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/typescript-estree": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", + "@typescript-eslint/scope-manager": "6.14.0", + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/typescript-estree": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0", "debug": "^4.3.4" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -530,16 +474,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz", - "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.14.0.tgz", + "integrity": "sha512-VT7CFWHbZipPncAZtuALr9y3EuzY1b1t1AEkIq2bTXUPKw+pHoXflGNG5L+Gv6nKul1cz1VH8fz16IThIU0tdg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1" + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -547,25 +491,25 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz", - "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.14.0.tgz", + "integrity": "sha512-x6OC9Q7HfYKqjnuNu5a7kffIYs3No30isapRBJl1iCHLitD8O0lFbRcVGiOcuyN837fqXzPZ1NS10maQzZMKqw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.7.1", - "@typescript-eslint/utils": "7.7.1", + "@typescript-eslint/typescript-estree": "6.14.0", + "@typescript-eslint/utils": "6.14.0", "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -574,12 +518,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz", - "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.14.0.tgz", + "integrity": "sha512-uty9H2K4Xs8E47z3SnXEPRNDfsis8JO27amp2GNCnzGETEW3yTqEIVg5+AI7U276oGF/tw6ZA+UesxeQ104ceA==", "dev": true, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -587,22 +531,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz", - "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.14.0.tgz", + "integrity": "sha512-yPkaLwK0yH2mZKFE/bXkPAkkFgOv15GJAUzgUVonAbv0Hr4PK/N2yaA/4XQbTZQdygiDkpt5DkxPELqHguNvyw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -615,41 +558,41 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz", - "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.14.0.tgz", + "integrity": "sha512-XwRTnbvRr7Ey9a1NT6jqdKX8y/atWG+8fAIu3z73HSP8h06i3r/ClMhmaF/RGWGW1tHJEwij1uEg2GbEmPYvYg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.15", - "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/typescript-estree": "7.7.1", - "semver": "^7.6.0" + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.14.0", + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/typescript-estree": "6.14.0", + "semver": "^7.5.4" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^7.0.0 || ^8.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz", - "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.14.0.tgz", + "integrity": "sha512-fB5cw6GRhJUz03MrROVuj5Zm/Q+XWlVdIsFj+Zb1Hvqouc8t+XP2H5y53QYU/MGtd2dPg6/vJJlhoX3xc2ehfw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "6.14.0", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -683,9 +626,9 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -780,13 +723,19 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" + }, "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/braces": { @@ -826,6 +775,14 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "engines": { + "node": "*" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -875,6 +832,14 @@ "node": ">= 8" } }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "engines": { + "node": "*" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -906,6 +871,15 @@ "node": ">=0.4.0" } }, + "node_modules/digest-fetch": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz", + "integrity": "sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==", + "dependencies": { + "base-64": "^0.1.0", + "md5": "^2.3.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -972,16 +946,16 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", + "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint/js": "8.55.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -1054,28 +1028,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -1189,9 +1141,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -1252,9 +1204,9 @@ } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, "node_modules/fold-to-ascii": { @@ -1341,28 +1293,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -1427,9 +1357,9 @@ } }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "dev": true, "engines": { "node": ">= 4" @@ -1476,6 +1406,11 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1539,19 +1474,6 @@ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, - "node_modules/json-schema-to-ts": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.0.1.tgz", - "integrity": "sha512-ANphQxnKbzLWPeYDmdoci8C9g9ttpfMx8etTlJJ8UCEmNXH9jxGkn3AAbMe+lR4N5OG/01nYxPrDyugLdsRt+A==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.18.3", - "ts-algebra": "^1.2.2" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -1630,9 +1552,19 @@ } }, "node_modules/magic-bytes.js": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.10.0.tgz", - "integrity": "sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ==" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.7.0.tgz", + "integrity": "sha512-YzVU2+/hrjwx8xcgAw+ffNq3jkactpj+f1iSL4LonrFKhvnwDzHSqtFdk/MMRP53y9ScouJ7cKEnqYsJwsHoYA==" + }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } }, "node_modules/merge2": { "version": "1.4.1", @@ -1676,18 +1608,15 @@ } }, "node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "*" } }, "node_modules/ms": { @@ -1748,14 +1677,15 @@ } }, "node_modules/openai": { - "version": "4.38.3", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.38.3.tgz", - "integrity": "sha512-mIL9WtrFNOanpx98mJ+X/wkoepcxdqqu0noWFoNQHl/yODQ47YM7NEYda7qp8JfjqpLFVxY9mQhshoS/Fqac0A==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.21.0.tgz", + "integrity": "sha512-HT0Jm2iGI5+Maq7Da/DPTeIAxNvpa5pamkhlNnJJAqJgVjaFDvMUBjGhFJoVohkYWwZjM9oSyfSC0eoVNPioaQ==", "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", + "digest-fetch": "^1.3.0", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7", @@ -1766,9 +1696,9 @@ } }, "node_modules/openai/node_modules/@types/node": { - "version": "18.19.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz", - "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==", + "version": "18.19.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz", + "integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==", "dependencies": { "undici-types": "~5.26.4" } @@ -1890,13 +1820,13 @@ } }, "node_modules/prisma": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.13.0.tgz", - "integrity": "sha512-kGtcJaElNRAdAGsCNykFSZ7dBKpL14Cbs+VaQ8cECxQlRPDjBlMHNFYeYt0SKovAVy2Y65JXQwB3A5+zIQwnTg==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.7.0.tgz", + "integrity": "sha512-0rcfXO2ErmGAtxnuTNHQT9ztL0zZheQjOI/VNJzdq87C3TlGPQtMqtM+KCwU6XtmkoEr7vbCQqA7HF9IY0ST+Q==", "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/engines": "5.13.0" + "@prisma/engines": "5.7.0" }, "bin": { "prisma": "build/index.js" @@ -1934,12 +1864,6 @@ } ] }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2006,9 +1930,9 @@ } }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -2109,28 +2033,22 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, - "node_modules/ts-algebra": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-1.2.2.tgz", - "integrity": "sha512-kloPhf1hq3JbCPOTYoOWDKxebWjNb2o/LKnNfkWhxVVisFFmMJPPdJeGoGmM+iRLyoXAR61e08Pb+vUXINg8aA==", - "dev": true - }, "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", "dev": true, "engines": { - "node": ">=16" + "node": ">=16.13.0" }, "peerDependencies": { "typescript": ">=4.2.0" } }, "node_modules/ts-mixer": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", - "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==" + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", + "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==" }, "node_modules/tslib": { "version": "2.6.2", @@ -2162,9 +2080,9 @@ } }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -2199,9 +2117,9 @@ } }, "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==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", "engines": { "node": ">= 8" } diff --git a/package.json b/package.json index 870f9c7..4af91ed 100644 --- a/package.json +++ b/package.json @@ -11,21 +11,20 @@ "author": "Wroclaw", "license": "MIT", "dependencies": { - "@prisma/client": "5.13.0", - "discord.js": "14.14.1", + "@prisma/client": "5.7.0", + "discord.js": "^14.8.0", "fold-to-ascii": "^5.0.1", "gpt-3-encoder": "^1.1.4", - "openai": "^4.38.3", + "openai": "^4.10.0", "require-directory": "^2.1.1", - "typescript": "^5.4.5" + "typescript": "^5.1.6" }, "devDependencies": { "@types/fold-to-ascii": "^5.0.0", "@types/require-directory": "^2.1.2", - "@typescript-eslint/eslint-plugin": "^7.7.1", - "@typescript-eslint/parser": "^7.7.1", - "eslint": "^8.57.0", - "json-schema-to-ts": "^3.0.1", - "prisma": "5.13.0" + "@typescript-eslint/eslint-plugin": "^6.2.0", + "@typescript-eslint/parser": "^6.2.0", + "eslint": "^8.46.0", + "prisma": "5.7.0" } } diff --git a/scripts/pushCommands.ts b/scripts/pushCommands.ts index 3c5f093..25ee04e 100644 --- a/scripts/pushCommands.ts +++ b/scripts/pushCommands.ts @@ -4,25 +4,13 @@ import { REST, RESTGetAPIOAuth2CurrentApplicationResult, RESTPostAPIApplicationC import { config } from "../src/index"; import requireDirectory from "require-directory"; -import - Command -, { - ApplicationIntegrationType -, InteractionContextTypes -, InteractionTypeMap -} from "../src/command"; +import Command from "../src/command"; const post: RESTPostAPIApplicationCommandsJSONBody[] = []; const guildId = process.argv.slice(2)[0]; const importedCommands = requireDirectory(module, "../src/commands"); -function isGuildCommand(command: Command): boolean { - // guild Commmand is when it's a guild install and context is guild (and these are defaults if not provided) - return (command.integration_types?.includes(ApplicationIntegrationType.Guild_Install) ?? true) - && (command.contexts?.includes(InteractionContextTypes.Guild) ?? true); -} - for (const obj in importedCommands) { try { const allExports = importedCommands[obj] as {default: unknown}; @@ -31,10 +19,6 @@ for (const obj in importedCommands) { // @ts-expect-error const constructedExport = new defaultExport() as unknown; if (!(constructedExport instanceof Command)) throw new Error(`${obj}'s default does not extends Command`); - if (guildId && guildId !== "" && isGuildCommand(constructedExport as Command)) { - console.log(`Skipping ${obj} because it's not a guild command`); - continue; - } post.push(constructedExport.toRESTPostApplicationCommands()); } catch (e) { console.error(e); diff --git a/shell.nix b/shell.nix index 1759471..b520ade 100644 --- a/shell.nix +++ b/shell.nix @@ -1,16 +1,17 @@ -{ pkgs ? import {} -, unstable ? import {} -}: +{ pkgs ? import {} }: let - prisma-version = "5.13.0"; + # Updating this package will force an update for nodePackages.prisma. The + # version of prisma-engines and nodePackages.prisma must be the same for them to + # function correctly. + prisma-version = "5.7.0"; prisma-src = pkgs.fetchFromGitHub { owner = "prisma"; repo = "prisma-engines"; rev = prisma-version; - hash = "sha256-8LC2RV3FRr1F0TZxQNxvvEoTyhKusgzB5omlxLAnHG0="; + hash = "sha256-gZEz0UtgNwumsZbweAyx3TOVHJshpBigc9pzWN7Gb/A="; }; - new-prisma-engines = unstable.rustPlatform.buildRustPackage { + new-prisma-engines = pkgs.rustPlatform.buildRustPackage { pname = "prisma-engines"; version = prisma-version; @@ -29,10 +30,10 @@ let cargoLock = { lockFile = "${prisma-src}/Cargo.lock"; outputHashes = { - "cuid-1.3.2" = "sha256-qBu1k/dJiA6rWBwk4nOOqouIneD9h2TTBT8tvs0TDfA="; + "cuid-1.3.2" = "sha256-ZihFrLerEIOdbJggaBbByRbC1sZRvF4M0LN2albB7vA="; "barrel-0.6.6-alpha.0" = "sha256-USh0lQ1z+3Spgc69bRFySUzhuY79qprLlEExTmYWFN8="; "graphql-parser-0.3.0" = "sha256-0ZAsj2mW6fCLhwTETucjbu4rPNzfbNiHu2wVTBlTNe4="; - "mysql_async-0.31.3" = "sha256-2wOupQ/LFV9pUifqBLwTvA0tySv+XWbxHiqs7iTzvvg="; + "mysql_async-0.31.3" = "sha256-QIO9s0Upc0/1W7ux1RNJNGKqzO4gB4gMV3NoakAbxkQ="; "postgres-native-tls-0.5.0" = "sha256-UYPsxhCkXXWk8yPbqjNS0illwjS5mVm3Z/jFwpVwqfw="; }; }; @@ -61,6 +62,14 @@ let # Tests are long to compile doCheck = false; + + # meta = with lib; { + # description = "A collection of engines that power the core stack for Prisma"; + # homepage = "https://www.prisma.io/"; + # license = licenses.asl20; + # platforms = platforms.unix; + # maintainers = with maintainers; [ pimeys tomhoule ivan aqrln ]; + # }; }; in pkgs.mkShell { diff --git a/src/command.ts b/src/command.ts index 35be22a..d053e72 100644 --- a/src/command.ts +++ b/src/command.ts @@ -2,47 +2,12 @@ import { AutocompleteInteraction, PermissionsBitField } from "discord.js"; import { RESTPostAPIApplicationCommandsJSONBody } from "discord.js"; import { APIApplicationCommandOption, ApplicationCommandType, ChatInputCommandInteraction, LocalizationMap, MessageInteraction, PermissionResolvable, UserSelectMenuInteraction } from "discord.js"; -export type InteractionTypeMap = { - // [CommandType]: [Interaction, Description] +type InteractionTypeMap = { [ApplicationCommandType.ChatInput]: [ChatInputCommandInteraction, string]; [ApplicationCommandType.Message]: [MessageInteraction, never]; [ApplicationCommandType.User]: [UserSelectMenuInteraction, never]; }; -// TODO: At time of coding, Discord api types doesn't support user installations of bot/application yet -// replace this with the types from the discord api types when it's available -/** - * https://discord.com/developers/docs/resources/application#application-object-application-integration-types - */ -export enum ApplicationIntegrationType { - Guild_Install = 0, - User_Install = 1, -} - -/** - * https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-context-types - */ -export enum InteractionContextTypes { - Guild = 0, - BotDM = 1, - PrivateChannel = 2, -} - -/** - * https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-structure - */ -export type FutureRESTPostAPIApplicationCommandsJSONBody = - RESTPostAPIApplicationCommandsJSONBody -& { - /** - * @deprecated use contexts instead - */ - dm_permission?: boolean; - integration_types?: ApplicationIntegrationType[]; - contexts?: InteractionContextTypes[]; -}; - - interface Command { readonly name: string; readonly name_localizations?: LocalizationMap; @@ -52,10 +17,7 @@ interface Command { @@ -63,7 +25,7 @@ abstract class Command; - toRESTPostApplicationCommands(): FutureRESTPostAPIApplicationCommandsJSONBody { + toRESTPostApplicationCommands(): RESTPostAPIApplicationCommandsJSONBody { return { name: this.name, name_localizations: this.name_localizations, @@ -74,8 +36,6 @@ abstract class Command= userLimit.quota) { - interaction.reply({ - - embeds: [{ - color: 0xff0000, - description: "You've used up your quota,\n" + userLimit.toString(), - }], - ephemeral: true, - }).catch(e => { - console.error("Failed to reply to user: ", e); - }); - return; - } - - // TODO: check content in moderation API - - const messages: ChatCompletionMessageParam[] = [ - ...config.systemPrompt(interaction), - { role: "user", name: formatName(interaction.user.displayName), content } - ]; - - const [answer] = await Promise.all([ - executeChatCompletion(messages, interaction), - interaction.deferReply({ ephemeral }), - ]); - - await replyInMultiMessage(answer.choices[0].message.content, interaction); - } -} diff --git a/src/commands/check-quota.ts b/src/commands/check-quota.ts index 4cc61d4..3a2f5ef 100644 --- a/src/commands/check-quota.ts +++ b/src/commands/check-quota.ts @@ -1,10 +1,6 @@ import { ApplicationCommandType, ChatInputCommandInteraction, APIApplicationCommandOption, ApplicationCommandOptionType, APIEmbedField } from "discord.js"; -import - Command -,{ApplicationIntegrationType -, InteractionContextTypes -} from "../command"; +import Command from "../command"; import { config } from "../index"; export default class MyLimit extends Command implements Command { @@ -25,15 +21,6 @@ export default class MyLimit extends Command implements Command { required: false, } ]; - integration_types = [ - ApplicationIntegrationType.Guild_Install, - ApplicationIntegrationType.User_Install - ]; - contexts = [ - InteractionContextTypes.Guild, - InteractionContextTypes.BotDM, - InteractionContextTypes.PrivateChannel - ]; async execute(interaction: ChatInputCommandInteraction) { let recoveryFor = interaction.options.getInteger("recovery-for", false); diff --git a/src/commands/listen.ts b/src/commands/listen.ts deleted file mode 100644 index 3f1c39d..0000000 --- a/src/commands/listen.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {ApplicationCommandType, ChatInputCommandInteraction } from "discord.js"; - -import Command, { ApplicationIntegrationType, InteractionContextTypes } from "../command"; - -export default class Listen extends Command implements Command { - // This command exists because Discord bots don't receive direct messages - // unless they explicitly open a DM channel with the user - name = "listen"; - description = "Makes the bot listen on your direct messages"; - type = ApplicationCommandType.ChatInput; - - options = []; - integration_types = [ - ApplicationIntegrationType.Guild_Install, - ApplicationIntegrationType.User_Install - ]; - contexts = [InteractionContextTypes.BotDM]; - - async execute(interaction: ChatInputCommandInteraction) { - await interaction.user.createDM(); - await interaction.reply({ - content: "I'm now listening to your direct messages", - ephemeral: true, - }); - } -} diff --git a/src/configDefault.ts b/src/configDefault.ts index 130b1a2..65785a9 100644 --- a/src/configDefault.ts +++ b/src/configDefault.ts @@ -1,8 +1,4 @@ -import { - ActivityType -, type PresenceStatusData -, type PresenceData -} from "discord.js"; +import { Message } from "discord.js"; import { ChatCompletionMessageParam as OpenAIMessage, ChatCompletionCreateParamsNonStreaming as ChatCompletionRequestData, @@ -10,20 +6,18 @@ import { import IQuota from "./IQuota"; import MessageCount from "./quota/messageCount"; -import { apiRequest } from "./execution"; export interface IConfigRequired { + readonly calendarParams: Intl.DateTimeFormatOptions; /** Tokens to authentiate with */ readonly tokens: { readonly Discord: string; readonly OpenAI: string; }; - /** Discord bot status */ - readonly status: PresenceData /** Messages to append at the start of every chat history when sending to API */ - systemPrompt(context: apiRequest): OpenAIMessage[]; + systemPrompt(context: Message): OpenAIMessage[]; /** OpenAI model config */ - readonly chatCompletionParams: Omit; + readonly chatCompletionParams: Omit; /** Limits for message selection */ readonly readLimits: { /** Maximum message age to include (in miliseconds) */ @@ -46,10 +40,6 @@ export default function newConfig(config?: IConfig): IConfigRequired { return { ...defaultConfig, ...config }; } -function isEnvDefined(key: string): boolean { - return process.env[key] !== undefined; -} - function envAsString(key: string): string | undefined { key = key.toLocaleUpperCase(); return process.env[key]; @@ -61,54 +51,16 @@ function envAsNumber(key: string): number | undefined { return !Number.isNaN(value) ? value : undefined; } -function envAsBoolean(key: string): boolean | undefined { - key = key.toUpperCase(); - const value = process.env[key]; - return !(value === "false" || value === "0"); -} - -function envAsActivityType(key: string): ActivityType | undefined { - key = key.toUpperCase(); - const value = process.env[key]?.toUpperCase(); - switch (value) { - case "0": - case "PLAYING": - return ActivityType.Playing; - case "1": - case "STREAMING": - return ActivityType.Streaming; - case "2": - case "LISTENING": - return ActivityType.Listening; - case "3": - case "WATCHING": - return ActivityType.Watching; - case "4": - case "CUSTOM": - return ActivityType.Custom; - case "5": - case "COMPETING": - return ActivityType.Competing; - default: - return undefined; - } -} - -function envAsPresenceStatusData(key: string): PresenceStatusData | undefined { - key = key.toUpperCase(); - const value = process.env[key]?.toLowerCase(); - switch (value) { - case "online": - case "idle": - case "dnd": - case "invisible": - return value; - default: - return undefined; - } -} - const defaultConfig: IConfigRequired = { + calendarParams: { + weekday: "short", + year: "numeric", + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + hour12: false, + }, tokens: { Discord: envAsString("TOKENS__DISCORD") ?? "", OpenAI: envAsString("TOKENS__OPENAI") ?? "", @@ -123,16 +75,6 @@ const defaultConfig: IConfigRequired = { }, ]; }, - status: { - activities: isEnvDefined("STATUS__NAME") ? [{ - name: envAsString("STATUS__NAME") as string, - type: envAsActivityType("STATUS__TYPE") ?? ActivityType.Custom, - state: envAsString("STATUS__STATE"), - url: envAsString("STATUS__URL"), - }] : undefined, - status: envAsPresenceStatusData("STATUS__STATUS"), - afk: envAsBoolean("STATUS__AFK"), - }, chatCompletionParams: { model: envAsString("CHAT_COMPLETION_PARAMS__MODEL") ?? "gpt-3.5-turbo", max_tokens: envAsNumber("CHAT_COMPLETION_PARAMS__MAX_TOKENS") ?? 384, diff --git a/src/execution.ts b/src/execution.ts index 8c550af..1f4b282 100644 --- a/src/execution.ts +++ b/src/execution.ts @@ -73,7 +73,7 @@ export function getAuthor(request: apiRequest) { * @returns Promise of the done action */ function requestReply( - request: apiRequest, + request: RequestMessage, message: DiscordApi.MessageReplyOptions & DiscordApi.InteractionReplyOptions, // TODO: add support for these below replyOptions: DiscordApi.MessageReplyOptions = {}, @@ -172,42 +172,29 @@ export async function queueRequest(request: apiRequest) { * Logs used tokens to the terminal and to the database * @param answer the response that OpenAI returned * @param message the message that initiated the execution - * @param functionRan counter of how many function have been ran (to distinct records in database) + * @param functionRan counter of how many function have been ran */ function logUsedTokens( answer: ChatCompletion, - message: apiRequest | undefined = undefined, - functionRan: number = 0, + message: RequestMessage, + functionRan: number, ) { const usage = answer.usage; - const functionNames = - answer.choices[0].message.tool_calls?.map( - v => v.type === "function" ? v.function.name : `[unknown type]` - ); + const functionName = answer.choices[0].message?.function_call?.name; if (usage !== undefined) { - if (!message) { - // log usage to stdout even if we can't store it in database - console.warn(`Used ${usage.total_tokens} (${usage.prompt_tokens} + ${usage.completion_tokens}) tokens from unknown call`); - // it doesn't make sense to store usage in database if we don't know where it came from - return; - } - const channelName: string = !message.channelId ? "[No channel]" - : !message.channel ? `[Unknown channel: ${message.channelId}]` - : !message.channel.isDMBased() ? `#${message.channel.name} (${message.guild?.name})` - : `#@${getAuthor(message).tag}` - ; - console.log(`Used ${usage.total_tokens} (${usage.prompt_tokens} + ${usage.completion_tokens}) tokens for ${getAuthor(message).tag} (${getAuthor(message).id}) in ${channelName}${functionNames && functionNames.length > 0 ? " [Tools: " + functionNames.join(", ") + "]" : ""}`); + const channelName: string = !message.channel.isDMBased() ? `${message.channel.name} (${message.guild?.name})` : `@${getAuthor(message).tag}`; + console.log(`Used ${usage.total_tokens} (${usage.prompt_tokens} + ${usage.completion_tokens}) tokens for ${getAuthor(message).tag} (${getAuthor(message).id}) in #${channelName}${functionName ? " [Function: " + functionName + "]" : ""}`); database.usage.create({ data: { timestamp: message.createdAt, user: BigInt(getAuthor(message).id), - channel: BigInt(message.channelId ?? 0), + channel: BigInt(message.channelId), guild: message.guildId ? BigInt(message.guildId) : null, usageRequest: usage.prompt_tokens, usageResponse: usage.completion_tokens, - functionName: functionNames?.join(", ") ?? null, - functionRan: functionRan, + functionName: functionName ?? null, + functionRan: functionName ? functionRan : 0, } }).catch((e => { console.error("Failed to push to a database"); @@ -223,7 +210,9 @@ function logUsedTokens( async function executeFromQueue(channel: string) { const channelQueue = channelsRunning.get(channel) as ChannelsRunningValue; const message = channelQueue.at(0) as RequestMessage; + let functionRanCounter = 0; let OpenAImessages: ChatCompletionMessageParam[] = []; + let modelUsernameMap: Map; // ignore if we can't even send anything to reply if (!canReplyToRequest(message)) return; @@ -249,14 +238,57 @@ async function executeFromQueue(channel: string) { return b.createdTimestamp - a.createdTimestamp; }); - OpenAImessages = toOpenAIMessages(messages.values()); - const answer = await executeChatCompletion(OpenAImessages, message); + [OpenAImessages, modelUsernameMap] = toOpenAIMessages(messages.values()); + let generatedMessage: ChatCompletionMessage | undefined = undefined; + let answer: Awaited>; + + do { + answer = await openai.chat.completions.create({ + ...config.chatCompletionParams, + messages: OpenAImessages, + // FIXME: don't use new instance of FunctionManager + functions: new FunctionManager().getFunctions(), + }); + + logUsedTokens(answer, message, ++functionRanCounter); + + generatedMessage = answer.choices[0].message; + if (!generatedMessage) throw new Error("Empty message received"); + + // handle function calls + if (generatedMessage.function_call) { + OpenAImessages.push(generatedMessage); + // FIXME: don't use new instance of FunctionManager + OpenAImessages.push( + new FunctionManager().handleFunction(generatedMessage.function_call, modelUsernameMap) + ); + } + } while (generatedMessage.function_call); channelQueue.stopTyping(); const answerContent = answer.choices[0].message?.content; - await replyInMultiMessage(answerContent, message); + if (answerContent === null || answerContent === "") { + if (message instanceof DiscordApi.Message) message.react("😶").catch(() => {/* GRACEFAIL: It's okay if the bot won't reply */}); + } + else { + const answerMessagesContent :string[] = [""]; + for (const i of answerContent.split(/\n\n/)) { + if (answerMessagesContent[answerMessagesContent.length-1].length + i.length < 2000) { + answerMessagesContent[answerMessagesContent.length-1] += "\n\n" + i; + } + else { + answerMessagesContent.push(i); + } + } + + for (const i of answerMessagesContent) { + const response = requestReply(message, {content: i}, {allowedMentions: { repliedUser: false }}); + + await response.then(rval => Moderation.checkMessageNoReturn(rval)); + } + } } catch (e) { let errorText: string = ""; channelQueue.stopTyping(); @@ -310,70 +342,3 @@ async function executeFromQueue(channel: string) { else return executeFromQueue(channel); } - -/** - * Replies to a message and splits to multiple messages if needed. - * @param answerContent - The content of the answer. - * @param message - The request message to reply to. - */ -export async function replyInMultiMessage(answerContent: string | null, message: apiRequest) { - if (answerContent === null || answerContent === "") { - if (message instanceof DiscordApi.Message) message.react("😶").catch(() => { }); - } - else { - const answerMessagesContent: string[] = [""]; - for (const i of answerContent.split(/\n\n/)) { - if (answerMessagesContent[answerMessagesContent.length - 1].length + i.length < 2000) { - answerMessagesContent[answerMessagesContent.length - 1] += "\n\n" + i; - } - else { - answerMessagesContent.push(i); - } - } - - for (const i of answerMessagesContent) { - const response = requestReply(message, { content: i }, { allowedMentions: { repliedUser: false } }); - - await response.then(rval => Moderation.checkMessageNoReturn(rval)); - } - } -} - -/** - * Executes the chat completion process. - * - * @param OpenAImessages An array of ChatCompletionMessageParam objects representing the messages for chat completion. - * @param message An optional RequestMessage object representing the request message, used for logging. - * @returns A Promise that resolves to the answer from the chat completion process. - */ -export async function executeChatCompletion( - OpenAImessages: ChatCompletionMessageParam[], - message: apiRequest | undefined, -) { - let generatedMessage: ChatCompletionMessage | undefined = undefined; - let answer: Awaited>; - let functionRanCounter = 0; - - do { - answer = await openai.chat.completions.create({ - ...config.chatCompletionParams, - messages: OpenAImessages, - // FIXME: don't use new instance of FunctionManager - tools: new FunctionManager().getToolsForOpenAi(), - }); - - functionRanCounter += answer.choices[0].message?.tool_calls?.length ?? 0; - logUsedTokens(answer, message, ++functionRanCounter); - - generatedMessage = answer.choices[0].message; - if (!generatedMessage) throw new Error("Empty message received"); - - // handle tool calls - if (generatedMessage.tool_calls !== undefined && generatedMessage.tool_calls.length > 0) { - OpenAImessages.push(generatedMessage); - // FIXME: don't use new instance of FunctionManager - OpenAImessages.push(...(await new FunctionManager().handleToolCalls(generatedMessage.tool_calls))); - } - } while (generatedMessage.tool_calls !== undefined && generatedMessage.tool_calls.length > 0); - return answer; -} diff --git a/src/funcitonManager.ts b/src/funcitonManager.ts index 4860c0c..9af00d5 100644 --- a/src/funcitonManager.ts +++ b/src/funcitonManager.ts @@ -1,43 +1,52 @@ -import { FunctionDefinition } from "openai/resources"; -import { - ChatCompletionMessageParam -, ChatCompletionMessageToolCall -, ChatCompletionTool -} from "openai/resources/chat"; -import { type FromSchema, type JSONSchema } from "json-schema-to-ts"; +import { ChatCompletionCreateParams, ChatCompletionMessage, ChatCompletionMessageParam } from "openai/resources/chat"; -type OpenAIFunctionRequestData = (JSONSchema & { - type: "object" -}); +import { config } from "./index"; -type ChatCompletionToolDefinition = ChatCompletionTool; -type ChatCompletionToolCall = ChatCompletionMessageToolCall; +type parameterMap = { + string: string, + number: number, +}; -type ChatCompletionFunctionDefinition = FunctionDefinition; +type nameTypeMap = {[name: string]: keyof parameterMap} | Record; + +type OpenAIFunctionRequestData = { + [name in keyof T]: T[name]; +}; + +type ChatCompletionFunctions = ChatCompletionCreateParams.Function; +type ChatCompletionFunctionCall = ChatCompletionMessage.FunctionCall; /** * Represents the function that can be ran by the OpenAI model */ -export interface OpenAIFunction< - T extends Readonly = Readonly -> { +export interface OpenAIFunction { name: string, description?: string, - parameters: T, + parameters: { + type: "object", + properties: T extends Record ? Record : { + [name in T[string]]: { + type: T[name], + description?: string, + } + }, + required?: Array, + }, } -export abstract class OpenAIFunction< - T extends Readonly = Readonly -> { - getSettings(): ChatCompletionFunctionDefinition { +export abstract class OpenAIFunction { + getSettings(): ChatCompletionFunctions { return { name: this.name, description: this.description, - parameters: this.parameters as Record, + parameters: this.parameters, }; } - abstract execute(data: FromSchema): Promise; + abstract execute( + data: OpenAIFunctionRequestData, + modelUsernameMap: Map, + ): string; } /* @@ -47,70 +56,63 @@ export default class FunctionManager { store = new Map(); constructor() { - // TODO: import functions from functions directory + this.store.set("getTime", new GetTime()); } - public getTools(): ChatCompletionToolDefinition[] { - const rvalue: ChatCompletionToolDefinition[] = []; + public getFunctions(): ChatCompletionFunctions[] { + const rvalue: ChatCompletionFunctions[] = []; for (const [, value] of this.store) { - rvalue.push({type: "function", function: value.getSettings()}); + rvalue.push(value.getSettings()); } return rvalue; } - public getToolsForOpenAi(): ChatCompletionTool[] | undefined { - const rvalue = this.getTools(); - return rvalue.length > 0 ? rvalue : undefined; - } - - public handleFunction(request: ChatCompletionToolCall): Promise { + public handleFunction( + request: ChatCompletionFunctionCall, + modelUsernameMap: Map = new Map(), + ): ChatCompletionMessageParam { // eslint-disable-next-line @typescript-eslint/no-explicit-any let parsedArguments: any; - const functionToRun = this.store.get(request.function.name); + const functionToRun = this.store.get(request.name ?? ""); // check if the function is registered if (!functionToRun) { - return Promise.resolve({ + return { role: "system", - content: `Only use functions that were provided to you (response for tool call ID: ${request.id})`, - }); + content: "Only use functions that were provided to you", + }; } try { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - parsedArguments = JSON.parse(request.function.arguments); + parsedArguments = JSON.parse(request.arguments ?? ""); } catch (e) { - console.error("Function arguments raw: " + request.function.arguments); - throw new Error(`Failed to parse the function JSON arguments when running function [${request.function.name}]`, {cause: e}); + console.error("Function arguments raw: " + request.arguments); + throw new Error(`Failed to parse the function JSON arguments when running function [${request.name}]`, {cause: e}); } // FIXME: Verify if the parsedArguments matches the requested function argument declaration. - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - return functionToRun.execute(parsedArguments).then(content => { - return { - role: "tool", - tool_call_id: request.id, - content: content, - }; - }); - } - - public handleToolCall(call: ChatCompletionToolCall): Promise { - if (call.type === "function") { - return this.handleFunction(call); - } - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - throw new Error(`Unsupported tool call type: ${call.type || "never"}`); - } - - public handleToolCalls(calls: ChatCompletionToolCall[]) { - const rvalue: Promise[] = []; - for (const call of calls) { - if (call.type === "function") { - rvalue.push(this.handleToolCall(call)); - } - } - return Promise.all(rvalue); + return { + role: "function", + name: request.name, + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + content: functionToRun.execute(parsedArguments, modelUsernameMap), + }; + } +} + +// buildins + +class GetTime extends OpenAIFunction> { + name = "getTime"; + description = "Gets current date and time with a timezone attached"; + parameters = { + type: "object" as const, + properties: {} as Record, + }; + + execute(): string { + return `${Intl.DateTimeFormat().resolvedOptions().timeZone}): ${new Date().toLocaleString("en-US", config.calendarParams)}`; } } diff --git a/src/index.ts b/src/index.ts index 38468b1..27e5c45 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,7 +11,6 @@ const discord = new DiscordApi.Client({ intents: [ DiscordApi.GatewayIntentBits.Guilds, DiscordApi.GatewayIntentBits.GuildMessages, - DiscordApi.GatewayIntentBits.DirectMessages, DiscordApi.GatewayIntentBits.MessageContent, ] }); @@ -55,29 +54,13 @@ interactionManager.bindClient(discord); discord.on("ready", event => { console.log(`Connected to Discord as ${event.user.tag} (${event.user.id})`); - event.user.setPresence(config.status); }); discord.on("messageCreate", message => { if (message.author.bot) return; - if (!message.channel.isDMBased()) { - if (!message.mentions.has(message.client.user, { ignoreEveryone: true })) return; - } + if (!message.mentions.has(message.client.user)) return; return queueRequest(message); }); -if (require.main === module) { - void discord.login(config.tokens.Discord); - process.on("SIGINT", () => { - console.log("got SIGINT, exiting"); - //FIXME: finish executing requests then exit - discord.destroy() - .then(() => process.exit()) - .catch((e) => { - console.error("Failed to gracefully exit"); - console.error(e); - process.exit(); - }); - }); -} +if (require.main === module) void discord.login(config.tokens.Discord); diff --git a/src/toOpenAIMessages.ts b/src/toOpenAIMessages.ts index 54ad00f..ccb8421 100644 --- a/src/toOpenAIMessages.ts +++ b/src/toOpenAIMessages.ts @@ -63,7 +63,7 @@ export function formatMessage(message: DiscordMessage): string { * @param name the name to format * @returns formatted name */ -export function formatName(name: string): string { +function formatName(name: string): string { // replace all characters to ascii equivelant return FoldToAscii.foldReplacing(name) // White spaces are not allowed @@ -95,28 +95,34 @@ function getAuthorUsername(message: DiscordMessage): string | undefined { /** * Converts the Iterable of Discord Messages to array of OpenAI Messages to send * first message in the interable will be the last of the returned array (reverse order) + * (first should be newest) * @param messages the iterable to convert - * @returns the converted messages + * @returns [0] the converted messages + * @returns [1] username mappings to id */ export default function toOpenAIMessages( messages: Iterable, -): OpenAIMessage[] { - const rvalue: OpenAIMessage[] = []; +): [OpenAIMessage[], Map] { + const rmessages: OpenAIMessage[] = []; + const rUserMap = new Map(); let tokenCount = 0; for (const message of messages) { + // FIXME: multiple users could have the same name here. const content = formatMessage(message); // FIXME: tokens are not being counted properly (it's lower than it is) but it's enough for me for now. tokenCount += countTokens(content); if (tokenCount > config.readLimits.tokens) break; - rvalue.push({ + const name = getAuthorUsername(message); + rmessages.push({ role: message.author.id === message.client.user.id ? "assistant" : "user", content: content, - name: getAuthorUsername(message), + name: name, }); + if (name && rUserMap.has(name)) rUserMap.set(name, message.author.id); } - rvalue.push(...config.systemPrompt([...messages][0]).reverse()); + rmessages.push(...config.systemPrompt([...messages][0]).reverse()); - return rvalue.reverse(); + return [rmessages.reverse(), rUserMap]; }