Compare commits

...
Sign in to create a new pull request.

21 commits

Author SHA1 Message Date
1b402c791c execution: log channel ID to terminal if it's unknown
channelId is set for commands executed outside of common guilds
no changes for usage logging in database is required
2024-04-26 08:13:29 +02:00
c4edf55f65 commands/ask: enforce userLimit 2024-04-26 08:07:46 +02:00
6f5f425166 configDefault: add status options 2024-04-26 07:14:41 +02:00
b1e464fe50 Dockerfile: create db directory 2024-04-26 06:14:57 +02:00
6efb6e5876 commands/ask: create
Allows to interact with the bot when bot is user installed in discord.
2024-04-26 05:41:53 +02:00
9f5dfefb31 execution: support for requests that don't have channel set
Interactions initiated outside of servers where bot is don't have channel assigned
2024-04-26 05:41:53 +02:00
2fab1b1b42 execution: factor out replying code to it's own fuction 2024-04-26 05:17:32 +02:00
482f72a4d1 execution: factor out chat completion process 2024-04-26 04:03:34 +02:00
d3567c3607 execution: handle undefined message in logUsedTokens 2024-04-26 04:02:09 +02:00
67a6e4d486 execution+configDefault: retrofit for tooll_calls api 2024-04-26 03:27:15 +02:00
370b7623b5 Dockerfile: chmod dist to 777 for config.ts compilation 2024-04-24 02:38:52 +02:00
b567e13f2a functionManager: use json-schema-to-ts to derive arguments for OpenAIFunctions 2024-04-24 02:27:31 +02:00
d9bee2dcf2 check-quota: define integration types and context to any 2024-04-23 21:11:40 +02:00
3c10f4ed6f Allow chatting with bot through direct messages
Added new command to make the bot see direct messages,
because by default these are not visible,
unless bot opens direct message with the user.
2024-04-23 21:10:52 +02:00
63cb52e7f4 Command: Add integration and context types
While discord api supports that, discord api types, which discord.js depends on does not.
2024-04-23 20:56:55 +02:00
0e5c8d22cc functionManager: retrofit for tool calls api 2024-04-23 17:46:24 +02:00
91232e99a7 Update dependencies 2024-04-23 16:47:08 +02:00
dc01146ee8 ignore @everyone mentions 2023-12-25 16:09:35 +01:00
74359067d0 functionManager: don't return empty function array for openai
openai doesn't accept empty function parameter,
it was discovered after I removed the testing buildin function
2023-12-13 21:08:09 +01:00
24e85f535a "Gracefully" exit when receiving sigint 2023-12-13 20:56:23 +01:00
02a5b0f7b9 Remove getTime model function
it lead to higher usage of tokens.
2023-12-13 17:42:59 +01:00
14 changed files with 782 additions and 396 deletions

View file

@ -15,5 +15,17 @@ COPY src ./src
COPY scripts ./scripts COPY scripts ./scripts
RUN npx tsc 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 # Run the app
CMD ["node", "dist/src/index.js"] CMD ["node", "dist/src/index.js"]
STOPSIGNAL SIGINT

548
package-lock.json generated
View file

@ -9,21 +9,22 @@
"version": "0.1.0", "version": "0.1.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@prisma/client": "5.7.0", "@prisma/client": "5.13.0",
"discord.js": "^14.8.0", "discord.js": "14.14.1",
"fold-to-ascii": "^5.0.1", "fold-to-ascii": "^5.0.1",
"gpt-3-encoder": "^1.1.4", "gpt-3-encoder": "^1.1.4",
"openai": "^4.10.0", "openai": "^4.38.3",
"require-directory": "^2.1.1", "require-directory": "^2.1.1",
"typescript": "^5.1.6" "typescript": "^5.4.5"
}, },
"devDependencies": { "devDependencies": {
"@types/fold-to-ascii": "^5.0.0", "@types/fold-to-ascii": "^5.0.0",
"@types/require-directory": "^2.1.2", "@types/require-directory": "^2.1.2",
"@typescript-eslint/eslint-plugin": "^6.2.0", "@typescript-eslint/eslint-plugin": "^7.7.1",
"@typescript-eslint/parser": "^6.2.0", "@typescript-eslint/parser": "^7.7.1",
"eslint": "^8.46.0", "eslint": "^8.57.0",
"prisma": "5.7.0" "json-schema-to-ts": "^3.0.1",
"prisma": "5.13.0"
} }
}, },
"node_modules/@aashutoshrathi/word-wrap": { "node_modules/@aashutoshrathi/word-wrap": {
@ -35,6 +36,18 @@
"node": ">=0.10.0" "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": { "node_modules/@discordjs/builders": {
"version": "1.7.0", "version": "1.7.0",
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.7.0.tgz", "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.7.0.tgz",
@ -180,37 +193,81 @@
"url": "https://opencollective.com/eslint" "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": { "node_modules/@eslint/js": {
"version": "8.55.0", "version": "8.57.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
"integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
} }
}, },
"node_modules/@fastify/busboy": { "node_modules/@fastify/busboy": {
"version": "2.1.0", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
"integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
"engines": { "engines": {
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/@humanwhocodes/config-array": { "node_modules/@humanwhocodes/config-array": {
"version": "0.11.13", "version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
"integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@humanwhocodes/object-schema": "^2.0.1", "@humanwhocodes/object-schema": "^2.0.2",
"debug": "^4.1.1", "debug": "^4.3.1",
"minimatch": "^3.0.5" "minimatch": "^3.0.5"
}, },
"engines": { "engines": {
"node": ">=10.10.0" "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": { "node_modules/@humanwhocodes/module-importer": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
@ -225,9 +282,9 @@
} }
}, },
"node_modules/@humanwhocodes/object-schema": { "node_modules/@humanwhocodes/object-schema": {
"version": "2.0.1", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
"integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
"dev": true "dev": true
}, },
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
@ -266,9 +323,9 @@
} }
}, },
"node_modules/@prisma/client": { "node_modules/@prisma/client": {
"version": "5.7.0", "version": "5.13.0",
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.7.0.tgz", "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.13.0.tgz",
"integrity": "sha512-cZmglCrfNbYpzUtz7HscVHl38e9CrUs31nrVoGUK1nIPXGgt8hT4jj2s657UXcNdQ/jBUxDgGmHyu2Nyrq1txg==", "integrity": "sha512-uYdfpPncbZ/syJyiYBwGZS8Gt1PTNoErNYMuqHDa2r30rNSFtgTA/LXsSk55R7pdRTMi5pHkeP9B14K6nHmwkg==",
"hasInstallScript": true, "hasInstallScript": true,
"engines": { "engines": {
"node": ">=16.13" "node": ">=16.13"
@ -283,70 +340,69 @@
} }
}, },
"node_modules/@prisma/debug": { "node_modules/@prisma/debug": {
"version": "5.7.0", "version": "5.13.0",
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.7.0.tgz", "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.13.0.tgz",
"integrity": "sha512-tZ+MOjWlVvz1kOEhNYMa4QUGURY+kgOUBqLHYIV8jmCsMuvA1tWcn7qtIMLzYWCbDcQT4ZS8xDgK0R2gl6/0wA==", "integrity": "sha512-699iqlEvzyCj9ETrXhs8o8wQc/eVW+FigSsHpiskSFydhjVuwTJEfj/nIYqTaWFYuxiWQRfm3r01meuW97SZaQ==",
"devOptional": true "devOptional": true
}, },
"node_modules/@prisma/engines": { "node_modules/@prisma/engines": {
"version": "5.7.0", "version": "5.13.0",
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.7.0.tgz", "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.13.0.tgz",
"integrity": "sha512-TkOMgMm60n5YgEKPn9erIvFX2/QuWnl3GBo6yTRyZKk5O5KQertXiNnrYgSLy0SpsKmhovEPQb+D4l0SzyE7XA==", "integrity": "sha512-hIFLm4H1boj6CBZx55P4xKby9jgDTeDG0Jj3iXtwaaHmlD5JmiDkZhh8+DYWkTGchu+rRF36AVROLnk0oaqhHw==",
"devOptional": true, "devOptional": true,
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@prisma/debug": "5.7.0", "@prisma/debug": "5.13.0",
"@prisma/engines-version": "5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9", "@prisma/engines-version": "5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b",
"@prisma/fetch-engine": "5.7.0", "@prisma/fetch-engine": "5.13.0",
"@prisma/get-platform": "5.7.0" "@prisma/get-platform": "5.13.0"
} }
}, },
"node_modules/@prisma/engines-version": { "node_modules/@prisma/engines-version": {
"version": "5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9", "version": "5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b",
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9.tgz", "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b.tgz",
"integrity": "sha512-V6tgRVi62jRwTm0Hglky3Scwjr/AKFBFtS+MdbsBr7UOuiu1TKLPc6xfPiyEN1+bYqjEtjxwGsHgahcJsd1rNg==", "integrity": "sha512-AyUuhahTINGn8auyqYdmxsN+qn0mw3eg+uhkp8zwknXYIqoT3bChG4RqNY/nfDkPvzWAPBa9mrDyBeOnWSgO6A==",
"devOptional": true "devOptional": true
}, },
"node_modules/@prisma/fetch-engine": { "node_modules/@prisma/fetch-engine": {
"version": "5.7.0", "version": "5.13.0",
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.7.0.tgz", "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.13.0.tgz",
"integrity": "sha512-zIn/qmO+N/3FYe7/L9o+yZseIU8ivh4NdPKSkQRIHfg2QVTVMnbhGoTcecbxfVubeTp+DjcbjS0H9fCuM4W04w==", "integrity": "sha512-Yh4W+t6YKyqgcSEB3odBXt7QyVSm0OQlBSldQF2SNXtmOgMX8D7PF/fvH6E6qBCpjB/yeJLy/FfwfFijoHI6sA==",
"devOptional": true, "devOptional": true,
"dependencies": { "dependencies": {
"@prisma/debug": "5.7.0", "@prisma/debug": "5.13.0",
"@prisma/engines-version": "5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9", "@prisma/engines-version": "5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b",
"@prisma/get-platform": "5.7.0" "@prisma/get-platform": "5.13.0"
} }
}, },
"node_modules/@prisma/get-platform": { "node_modules/@prisma/get-platform": {
"version": "5.7.0", "version": "5.13.0",
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.7.0.tgz", "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.13.0.tgz",
"integrity": "sha512-ZeV/Op4bZsWXuw5Tg05WwRI8BlKiRFhsixPcAM+5BKYSiUZiMKIi713tfT3drBq8+T0E1arNZgYSA9QYcglWNA==", "integrity": "sha512-B/WrQwYTzwr7qCLifQzYOmQhZcFmIFhR81xC45gweInSUn2hTEbfKUPd2keAog+y5WI5xLAFNJ3wkXplvSVkSw==",
"devOptional": true, "devOptional": true,
"dependencies": { "dependencies": {
"@prisma/debug": "5.7.0" "@prisma/debug": "5.13.0"
} }
}, },
"node_modules/@sapphire/async-queue": { "node_modules/@sapphire/async-queue": {
"version": "1.5.1", "version": "1.5.2",
"resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.1.tgz", "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.2.tgz",
"integrity": "sha512-1RdpsmDQR/aWfp8oJzPtn4dNQrbpqSL5PIA0uAB/XwerPXUf994Ug1au1e7uGcD7ei8/F63UDjr5GWps1g/HxQ==", "integrity": "sha512-7X7FFAA4DngXUl95+hYbUF19bp1LGiffjJtu7ygrZrbdCSsdDDBaSjB7Akw0ZbOu6k0xpXyljnJ6/RZUvLfRdg==",
"engines": { "engines": {
"node": ">=v14.0.0", "node": ">=v14.0.0",
"npm": ">=7.0.0" "npm": ">=7.0.0"
} }
}, },
"node_modules/@sapphire/shapeshift": { "node_modules/@sapphire/shapeshift": {
"version": "3.9.4", "version": "3.9.7",
"resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.4.tgz", "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.7.tgz",
"integrity": "sha512-SiOoCBmm8O7QuadLJnX4V0tAkhC54NIOZJtmvw+5zwnHaiulGkjY02wxCuK8Gf4V540ILmGz+UulC0U8mrOZjg==", "integrity": "sha512-4It2mxPSr4OGn4HSQWGmhFMsNFGfFVhWeRPCRwbH972Ek2pzfGRZtb0pJ4Ze6oIzcyh2jw7nUDa6qGlWofgd9g==",
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
"lodash": "^4.17.21" "lodash": "^4.17.21"
}, },
"engines": { "engines": {
"node": ">=v14.0.0", "node": ">=v16"
"npm": ">=7.0.0"
} }
}, },
"node_modules/@sapphire/snowflake": { "node_modules/@sapphire/snowflake": {
@ -371,17 +427,17 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.10.4", "version": "20.12.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
"integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==", "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
"dependencies": { "dependencies": {
"undici-types": "~5.26.4" "undici-types": "~5.26.4"
} }
}, },
"node_modules/@types/node-fetch": { "node_modules/@types/node-fetch": {
"version": "2.6.9", "version": "2.6.11",
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.9.tgz", "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz",
"integrity": "sha512-bQVlnMLFJ2d35DkPNjEPmd9ueO/rh5EiaZt2bhqiSarPjZIuIV6bPQVqcrEyvNo+AfTrRGVazle1tl597w3gfA==", "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==",
"dependencies": { "dependencies": {
"@types/node": "*", "@types/node": "*",
"form-data": "^4.0.0" "form-data": "^4.0.0"
@ -397,9 +453,9 @@
} }
}, },
"node_modules/@types/semver": { "node_modules/@types/semver": {
"version": "7.5.6", "version": "7.5.8",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
"integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
"dev": true "dev": true
}, },
"node_modules/@types/ws": { "node_modules/@types/ws": {
@ -411,33 +467,33 @@
} }
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "6.14.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.14.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz",
"integrity": "sha512-1ZJBykBCXaSHG94vMMKmiHoL0MhNHKSVlcHVYZNw+BKxufhqQVTOawNpwwI1P5nIFZ/4jLVop0mcY6mJJDFNaw==", "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.5.1", "@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "6.14.0", "@typescript-eslint/scope-manager": "7.7.1",
"@typescript-eslint/type-utils": "6.14.0", "@typescript-eslint/type-utils": "7.7.1",
"@typescript-eslint/utils": "6.14.0", "@typescript-eslint/utils": "7.7.1",
"@typescript-eslint/visitor-keys": "6.14.0", "@typescript-eslint/visitor-keys": "7.7.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"graphemer": "^1.4.0", "graphemer": "^1.4.0",
"ignore": "^5.2.4", "ignore": "^5.3.1",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
"semver": "^7.5.4", "semver": "^7.6.0",
"ts-api-utils": "^1.0.1" "ts-api-utils": "^1.3.0"
}, },
"engines": { "engines": {
"node": "^16.0.0 || >=18.0.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", "@typescript-eslint/parser": "^7.0.0",
"eslint": "^7.0.0 || ^8.0.0" "eslint": "^8.56.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"typescript": { "typescript": {
@ -446,26 +502,26 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "6.14.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.14.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz",
"integrity": "sha512-QjToC14CKacd4Pa7JK4GeB/vHmWFJckec49FR4hmIRf97+KXole0T97xxu9IFiPxVQ1DBWrQ5wreLwAGwWAVQA==", "integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "6.14.0", "@typescript-eslint/scope-manager": "7.7.1",
"@typescript-eslint/types": "6.14.0", "@typescript-eslint/types": "7.7.1",
"@typescript-eslint/typescript-estree": "6.14.0", "@typescript-eslint/typescript-estree": "7.7.1",
"@typescript-eslint/visitor-keys": "6.14.0", "@typescript-eslint/visitor-keys": "7.7.1",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
"node": "^16.0.0 || >=18.0.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"eslint": "^7.0.0 || ^8.0.0" "eslint": "^8.56.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"typescript": { "typescript": {
@ -474,16 +530,16 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "6.14.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.14.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz",
"integrity": "sha512-VT7CFWHbZipPncAZtuALr9y3EuzY1b1t1AEkIq2bTXUPKw+pHoXflGNG5L+Gv6nKul1cz1VH8fz16IThIU0tdg==", "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/types": "6.14.0", "@typescript-eslint/types": "7.7.1",
"@typescript-eslint/visitor-keys": "6.14.0" "@typescript-eslint/visitor-keys": "7.7.1"
}, },
"engines": { "engines": {
"node": "^16.0.0 || >=18.0.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@ -491,25 +547,25 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "6.14.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.14.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz",
"integrity": "sha512-x6OC9Q7HfYKqjnuNu5a7kffIYs3No30isapRBJl1iCHLitD8O0lFbRcVGiOcuyN837fqXzPZ1NS10maQzZMKqw==", "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/typescript-estree": "6.14.0", "@typescript-eslint/typescript-estree": "7.7.1",
"@typescript-eslint/utils": "6.14.0", "@typescript-eslint/utils": "7.7.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"ts-api-utils": "^1.0.1" "ts-api-utils": "^1.3.0"
}, },
"engines": { "engines": {
"node": "^16.0.0 || >=18.0.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"eslint": "^7.0.0 || ^8.0.0" "eslint": "^8.56.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"typescript": { "typescript": {
@ -518,12 +574,12 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "6.14.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.14.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz",
"integrity": "sha512-uty9H2K4Xs8E47z3SnXEPRNDfsis8JO27amp2GNCnzGETEW3yTqEIVg5+AI7U276oGF/tw6ZA+UesxeQ104ceA==", "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": "^16.0.0 || >=18.0.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@ -531,21 +587,22 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "6.14.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.14.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz",
"integrity": "sha512-yPkaLwK0yH2mZKFE/bXkPAkkFgOv15GJAUzgUVonAbv0Hr4PK/N2yaA/4XQbTZQdygiDkpt5DkxPELqHguNvyw==", "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/types": "6.14.0", "@typescript-eslint/types": "7.7.1",
"@typescript-eslint/visitor-keys": "6.14.0", "@typescript-eslint/visitor-keys": "7.7.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"globby": "^11.1.0", "globby": "^11.1.0",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
"semver": "^7.5.4", "minimatch": "^9.0.4",
"ts-api-utils": "^1.0.1" "semver": "^7.6.0",
"ts-api-utils": "^1.3.0"
}, },
"engines": { "engines": {
"node": "^16.0.0 || >=18.0.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@ -558,41 +615,41 @@
} }
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "6.14.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.14.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz",
"integrity": "sha512-XwRTnbvRr7Ey9a1NT6jqdKX8y/atWG+8fAIu3z73HSP8h06i3r/ClMhmaF/RGWGW1tHJEwij1uEg2GbEmPYvYg==", "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.4.0", "@eslint-community/eslint-utils": "^4.4.0",
"@types/json-schema": "^7.0.12", "@types/json-schema": "^7.0.15",
"@types/semver": "^7.5.0", "@types/semver": "^7.5.8",
"@typescript-eslint/scope-manager": "6.14.0", "@typescript-eslint/scope-manager": "7.7.1",
"@typescript-eslint/types": "6.14.0", "@typescript-eslint/types": "7.7.1",
"@typescript-eslint/typescript-estree": "6.14.0", "@typescript-eslint/typescript-estree": "7.7.1",
"semver": "^7.5.4" "semver": "^7.6.0"
}, },
"engines": { "engines": {
"node": "^16.0.0 || >=18.0.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"eslint": "^7.0.0 || ^8.0.0" "eslint": "^8.56.0"
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "6.14.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.14.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz",
"integrity": "sha512-fB5cw6GRhJUz03MrROVuj5Zm/Q+XWlVdIsFj+Zb1Hvqouc8t+XP2H5y53QYU/MGtd2dPg6/vJJlhoX3xc2ehfw==", "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/types": "6.14.0", "@typescript-eslint/types": "7.7.1",
"eslint-visitor-keys": "^3.4.1" "eslint-visitor-keys": "^3.4.3"
}, },
"engines": { "engines": {
"node": "^16.0.0 || >=18.0.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@ -626,9 +683,9 @@
} }
}, },
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.11.2", "version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
"integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
"dev": true, "dev": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
@ -723,19 +780,13 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true "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": { "node_modules/brace-expansion": {
"version": "1.1.11", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0"
"concat-map": "0.0.1"
} }
}, },
"node_modules/braces": { "node_modules/braces": {
@ -775,14 +826,6 @@
"url": "https://github.com/chalk/chalk?sponsor=1" "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": { "node_modules/color-convert": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@ -832,14 +875,6 @@
"node": ">= 8" "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": { "node_modules/debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -871,15 +906,6 @@
"node": ">=0.4.0" "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": { "node_modules/dir-glob": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@ -946,16 +972,16 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "8.55.0", "version": "8.57.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
"integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1", "@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.4", "@eslint/eslintrc": "^2.1.4",
"@eslint/js": "8.55.0", "@eslint/js": "8.57.0",
"@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/config-array": "^0.11.14",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8", "@nodelib/fs.walk": "^1.2.8",
"@ungap/structured-clone": "^1.2.0", "@ungap/structured-clone": "^1.2.0",
@ -1028,6 +1054,28 @@
"url": "https://opencollective.com/eslint" "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": { "node_modules/espree": {
"version": "9.6.1", "version": "9.6.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
@ -1141,9 +1189,9 @@
"dev": true "dev": true
}, },
"node_modules/fastq": { "node_modules/fastq": {
"version": "1.15.0", "version": "1.17.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
"integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"reusify": "^1.0.4" "reusify": "^1.0.4"
@ -1204,9 +1252,9 @@
} }
}, },
"node_modules/flatted": { "node_modules/flatted": {
"version": "3.2.9", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
"integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
"dev": true "dev": true
}, },
"node_modules/fold-to-ascii": { "node_modules/fold-to-ascii": {
@ -1293,6 +1341,28 @@
"node": ">=10.13.0" "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": { "node_modules/globals": {
"version": "13.24.0", "version": "13.24.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
@ -1357,9 +1427,9 @@
} }
}, },
"node_modules/ignore": { "node_modules/ignore": {
"version": "5.3.0", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
"integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">= 4" "node": ">= 4"
@ -1406,11 +1476,6 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true "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": { "node_modules/is-extglob": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@ -1474,6 +1539,19 @@
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
"dev": true "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": { "node_modules/json-schema-traverse": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@ -1552,19 +1630,9 @@
} }
}, },
"node_modules/magic-bytes.js": { "node_modules/magic-bytes.js": {
"version": "1.7.0", "version": "1.10.0",
"resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.7.0.tgz", "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.10.0.tgz",
"integrity": "sha512-YzVU2+/hrjwx8xcgAw+ffNq3jkactpj+f1iSL4LonrFKhvnwDzHSqtFdk/MMRP53y9ScouJ7cKEnqYsJwsHoYA==" "integrity": "sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ=="
},
"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": { "node_modules/merge2": {
"version": "1.4.1", "version": "1.4.1",
@ -1608,15 +1676,18 @@
} }
}, },
"node_modules/minimatch": { "node_modules/minimatch": {
"version": "3.1.2", "version": "9.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"brace-expansion": "^1.1.7" "brace-expansion": "^2.0.1"
}, },
"engines": { "engines": {
"node": "*" "node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/ms": { "node_modules/ms": {
@ -1677,15 +1748,14 @@
} }
}, },
"node_modules/openai": { "node_modules/openai": {
"version": "4.21.0", "version": "4.38.3",
"resolved": "https://registry.npmjs.org/openai/-/openai-4.21.0.tgz", "resolved": "https://registry.npmjs.org/openai/-/openai-4.38.3.tgz",
"integrity": "sha512-HT0Jm2iGI5+Maq7Da/DPTeIAxNvpa5pamkhlNnJJAqJgVjaFDvMUBjGhFJoVohkYWwZjM9oSyfSC0eoVNPioaQ==", "integrity": "sha512-mIL9WtrFNOanpx98mJ+X/wkoepcxdqqu0noWFoNQHl/yODQ47YM7NEYda7qp8JfjqpLFVxY9mQhshoS/Fqac0A==",
"dependencies": { "dependencies": {
"@types/node": "^18.11.18", "@types/node": "^18.11.18",
"@types/node-fetch": "^2.6.4", "@types/node-fetch": "^2.6.4",
"abort-controller": "^3.0.0", "abort-controller": "^3.0.0",
"agentkeepalive": "^4.2.1", "agentkeepalive": "^4.2.1",
"digest-fetch": "^1.3.0",
"form-data-encoder": "1.7.2", "form-data-encoder": "1.7.2",
"formdata-node": "^4.3.2", "formdata-node": "^4.3.2",
"node-fetch": "^2.6.7", "node-fetch": "^2.6.7",
@ -1696,9 +1766,9 @@
} }
}, },
"node_modules/openai/node_modules/@types/node": { "node_modules/openai/node_modules/@types/node": {
"version": "18.19.3", "version": "18.19.31",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz",
"integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==", "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==",
"dependencies": { "dependencies": {
"undici-types": "~5.26.4" "undici-types": "~5.26.4"
} }
@ -1820,13 +1890,13 @@
} }
}, },
"node_modules/prisma": { "node_modules/prisma": {
"version": "5.7.0", "version": "5.13.0",
"resolved": "https://registry.npmjs.org/prisma/-/prisma-5.7.0.tgz", "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.13.0.tgz",
"integrity": "sha512-0rcfXO2ErmGAtxnuTNHQT9ztL0zZheQjOI/VNJzdq87C3TlGPQtMqtM+KCwU6XtmkoEr7vbCQqA7HF9IY0ST+Q==", "integrity": "sha512-kGtcJaElNRAdAGsCNykFSZ7dBKpL14Cbs+VaQ8cECxQlRPDjBlMHNFYeYt0SKovAVy2Y65JXQwB3A5+zIQwnTg==",
"devOptional": true, "devOptional": true,
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@prisma/engines": "5.7.0" "@prisma/engines": "5.13.0"
}, },
"bin": { "bin": {
"prisma": "build/index.js" "prisma": "build/index.js"
@ -1864,6 +1934,12 @@
} }
] ]
}, },
"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": { "node_modules/require-directory": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@ -1930,9 +2006,9 @@
} }
}, },
"node_modules/semver": { "node_modules/semver": {
"version": "7.5.4", "version": "7.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"lru-cache": "^6.0.0" "lru-cache": "^6.0.0"
@ -2033,22 +2109,28 @@
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" "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": { "node_modules/ts-api-utils": {
"version": "1.0.3", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
"integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=16.13.0" "node": ">=16"
}, },
"peerDependencies": { "peerDependencies": {
"typescript": ">=4.2.0" "typescript": ">=4.2.0"
} }
}, },
"node_modules/ts-mixer": { "node_modules/ts-mixer": {
"version": "6.0.3", "version": "6.0.4",
"resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz",
"integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==" "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="
}, },
"node_modules/tslib": { "node_modules/tslib": {
"version": "2.6.2", "version": "2.6.2",
@ -2080,9 +2162,9 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.3.3", "version": "5.4.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
"integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@ -2117,9 +2199,9 @@
} }
}, },
"node_modules/web-streams-polyfill": { "node_modules/web-streams-polyfill": {
"version": "3.2.1", "version": "3.3.3",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
"engines": { "engines": {
"node": ">= 8" "node": ">= 8"
} }

View file

@ -11,20 +11,21 @@
"author": "Wroclaw", "author": "Wroclaw",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@prisma/client": "5.7.0", "@prisma/client": "5.13.0",
"discord.js": "^14.8.0", "discord.js": "14.14.1",
"fold-to-ascii": "^5.0.1", "fold-to-ascii": "^5.0.1",
"gpt-3-encoder": "^1.1.4", "gpt-3-encoder": "^1.1.4",
"openai": "^4.10.0", "openai": "^4.38.3",
"require-directory": "^2.1.1", "require-directory": "^2.1.1",
"typescript": "^5.1.6" "typescript": "^5.4.5"
}, },
"devDependencies": { "devDependencies": {
"@types/fold-to-ascii": "^5.0.0", "@types/fold-to-ascii": "^5.0.0",
"@types/require-directory": "^2.1.2", "@types/require-directory": "^2.1.2",
"@typescript-eslint/eslint-plugin": "^6.2.0", "@typescript-eslint/eslint-plugin": "^7.7.1",
"@typescript-eslint/parser": "^6.2.0", "@typescript-eslint/parser": "^7.7.1",
"eslint": "^8.46.0", "eslint": "^8.57.0",
"prisma": "5.7.0" "json-schema-to-ts": "^3.0.1",
"prisma": "5.13.0"
} }
} }

View file

@ -4,13 +4,25 @@ import { REST, RESTGetAPIOAuth2CurrentApplicationResult, RESTPostAPIApplicationC
import { config } from "../src/index"; import { config } from "../src/index";
import requireDirectory from "require-directory"; import requireDirectory from "require-directory";
import Command from "../src/command"; import
Command
, {
ApplicationIntegrationType
, InteractionContextTypes
, InteractionTypeMap
} from "../src/command";
const post: RESTPostAPIApplicationCommandsJSONBody[] = []; const post: RESTPostAPIApplicationCommandsJSONBody[] = [];
const guildId = process.argv.slice(2)[0]; const guildId = process.argv.slice(2)[0];
const importedCommands = requireDirectory(module, "../src/commands"); const importedCommands = requireDirectory(module, "../src/commands");
function isGuildCommand(command: Command<keyof InteractionTypeMap>): 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) { for (const obj in importedCommands) {
try { try {
const allExports = importedCommands[obj] as {default: unknown}; const allExports = importedCommands[obj] as {default: unknown};
@ -19,6 +31,10 @@ for (const obj in importedCommands) {
// @ts-expect-error // @ts-expect-error
const constructedExport = new defaultExport() as unknown; const constructedExport = new defaultExport() as unknown;
if (!(constructedExport instanceof Command)) throw new Error(`${obj}'s default does not extends Command`); if (!(constructedExport instanceof Command)) throw new Error(`${obj}'s default does not extends Command`);
if (guildId && guildId !== "" && isGuildCommand(constructedExport as Command<keyof InteractionTypeMap>)) {
console.log(`Skipping ${obj} because it's not a guild command`);
continue;
}
post.push(constructedExport.toRESTPostApplicationCommands()); post.push(constructedExport.toRESTPostApplicationCommands());
} catch (e) { } catch (e) {
console.error(e); console.error(e);

View file

@ -1,17 +1,16 @@
{ pkgs ? import <nixpkgs> {} }: { pkgs ? import <nixpkgs> {}
, unstable ? import <nixos-unstable> {}
}:
let let
# Updating this package will force an update for nodePackages.prisma. The prisma-version = "5.13.0";
# 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 { prisma-src = pkgs.fetchFromGitHub {
owner = "prisma"; owner = "prisma";
repo = "prisma-engines"; repo = "prisma-engines";
rev = prisma-version; rev = prisma-version;
hash = "sha256-gZEz0UtgNwumsZbweAyx3TOVHJshpBigc9pzWN7Gb/A="; hash = "sha256-8LC2RV3FRr1F0TZxQNxvvEoTyhKusgzB5omlxLAnHG0=";
}; };
new-prisma-engines = pkgs.rustPlatform.buildRustPackage { new-prisma-engines = unstable.rustPlatform.buildRustPackage {
pname = "prisma-engines"; pname = "prisma-engines";
version = prisma-version; version = prisma-version;
@ -30,10 +29,10 @@ let
cargoLock = { cargoLock = {
lockFile = "${prisma-src}/Cargo.lock"; lockFile = "${prisma-src}/Cargo.lock";
outputHashes = { outputHashes = {
"cuid-1.3.2" = "sha256-ZihFrLerEIOdbJggaBbByRbC1sZRvF4M0LN2albB7vA="; "cuid-1.3.2" = "sha256-qBu1k/dJiA6rWBwk4nOOqouIneD9h2TTBT8tvs0TDfA=";
"barrel-0.6.6-alpha.0" = "sha256-USh0lQ1z+3Spgc69bRFySUzhuY79qprLlEExTmYWFN8="; "barrel-0.6.6-alpha.0" = "sha256-USh0lQ1z+3Spgc69bRFySUzhuY79qprLlEExTmYWFN8=";
"graphql-parser-0.3.0" = "sha256-0ZAsj2mW6fCLhwTETucjbu4rPNzfbNiHu2wVTBlTNe4="; "graphql-parser-0.3.0" = "sha256-0ZAsj2mW6fCLhwTETucjbu4rPNzfbNiHu2wVTBlTNe4=";
"mysql_async-0.31.3" = "sha256-QIO9s0Upc0/1W7ux1RNJNGKqzO4gB4gMV3NoakAbxkQ="; "mysql_async-0.31.3" = "sha256-2wOupQ/LFV9pUifqBLwTvA0tySv+XWbxHiqs7iTzvvg=";
"postgres-native-tls-0.5.0" = "sha256-UYPsxhCkXXWk8yPbqjNS0illwjS5mVm3Z/jFwpVwqfw="; "postgres-native-tls-0.5.0" = "sha256-UYPsxhCkXXWk8yPbqjNS0illwjS5mVm3Z/jFwpVwqfw=";
}; };
}; };
@ -62,14 +61,6 @@ let
# Tests are long to compile # Tests are long to compile
doCheck = false; 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 in
pkgs.mkShell { pkgs.mkShell {

View file

@ -2,12 +2,47 @@ import { AutocompleteInteraction, PermissionsBitField } from "discord.js";
import { RESTPostAPIApplicationCommandsJSONBody } from "discord.js"; import { RESTPostAPIApplicationCommandsJSONBody } from "discord.js";
import { APIApplicationCommandOption, ApplicationCommandType, ChatInputCommandInteraction, LocalizationMap, MessageInteraction, PermissionResolvable, UserSelectMenuInteraction } from "discord.js"; import { APIApplicationCommandOption, ApplicationCommandType, ChatInputCommandInteraction, LocalizationMap, MessageInteraction, PermissionResolvable, UserSelectMenuInteraction } from "discord.js";
type InteractionTypeMap = { export type InteractionTypeMap = {
// [CommandType]: [Interaction, Description]
[ApplicationCommandType.ChatInput]: [ChatInputCommandInteraction, string]; [ApplicationCommandType.ChatInput]: [ChatInputCommandInteraction, string];
[ApplicationCommandType.Message]: [MessageInteraction, never]; [ApplicationCommandType.Message]: [MessageInteraction, never];
[ApplicationCommandType.User]: [UserSelectMenuInteraction, 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<Type extends keyof InteractionTypeMap = ApplicationCommandType> { interface Command<Type extends keyof InteractionTypeMap = ApplicationCommandType> {
readonly name: string; readonly name: string;
readonly name_localizations?: LocalizationMap; readonly name_localizations?: LocalizationMap;
@ -17,7 +52,10 @@ interface Command<Type extends keyof InteractionTypeMap = ApplicationCommandType
readonly default_member_permissions?: PermissionResolvable; readonly default_member_permissions?: PermissionResolvable;
readonly type: Type; readonly type: Type;
readonly nsfw?: boolean; readonly nsfw?: boolean;
/** @deprecated use contexts instead */
readonly dm_permission?: boolean; readonly dm_permission?: boolean;
readonly integration_types?: ApplicationIntegrationType[];
readonly contexts?: InteractionContextTypes[];
} }
abstract class Command<Type extends keyof InteractionTypeMap = ApplicationCommandType> { abstract class Command<Type extends keyof InteractionTypeMap = ApplicationCommandType> {
@ -25,7 +63,7 @@ abstract class Command<Type extends keyof InteractionTypeMap = ApplicationComman
autocomplete?(interaction: Type extends ApplicationCommandType.ChatInput ? AutocompleteInteraction : never ): Promise<void>; autocomplete?(interaction: Type extends ApplicationCommandType.ChatInput ? AutocompleteInteraction : never ): Promise<void>;
toRESTPostApplicationCommands(): RESTPostAPIApplicationCommandsJSONBody { toRESTPostApplicationCommands(): FutureRESTPostAPIApplicationCommandsJSONBody {
return { return {
name: this.name, name: this.name,
name_localizations: this.name_localizations, name_localizations: this.name_localizations,
@ -36,6 +74,8 @@ abstract class Command<Type extends keyof InteractionTypeMap = ApplicationComman
type: this.type, type: this.type,
nsfw: this.nsfw, nsfw: this.nsfw,
dm_permission: this.dm_permission, dm_permission: this.dm_permission,
integration_types: this.integration_types,
contexts: this.contexts,
}; };
} }
} }

90
src/commands/ask.ts Normal file
View file

@ -0,0 +1,90 @@
import {
APIApplicationCommandOption
, ApplicationCommandOptionType
, ApplicationCommandType
, ChatInputCommandInteraction
} from "discord.js";
import { ChatCompletionMessageParam } from "openai/resources";
import
Command
,{ApplicationIntegrationType
, InteractionContextTypes
} from "../command";
import { config } from "../index";
import { executeChatCompletion, replyInMultiMessage } from "../execution";
import { formatName } from "../toOpenAIMessages";
export default class Ask extends Command implements Command {
name = "ask";
description = "Promts the bot to reply to a single message without any history context";
type = ApplicationCommandType.ChatInput;
options: APIApplicationCommandOption[] = [
{
name: "content",
description: "The content of the prompt",
type: ApplicationCommandOptionType.String,
required: true,
},
{
name: "ephemeral",
description: "if true, only you can see the response (default true)",
type: ApplicationCommandOptionType.Boolean,
required: false,
}
];
integration_types = [
ApplicationIntegrationType.Guild_Install,
ApplicationIntegrationType.User_Install,
];
contexts = [
InteractionContextTypes.Guild,
InteractionContextTypes.BotDM,
InteractionContextTypes.PrivateChannel,
];
async execute(interaction: ChatInputCommandInteraction) {
const content = interaction.options.getString("content", true);
const ephemeral = interaction.options.getBoolean("ephemeral", false) ?? true;
if (!interaction.channel && !interaction.channelId) {
console.error("No channel found in interaction");
console.error(interaction);
await interaction.reply({
content: "No channel found in interaction???",
ephemeral: true
});
return;
}
const userLimit = await config.quota.checkUser(interaction.user, interaction);
if (userLimit.used >= 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);
}
}

View file

@ -1,6 +1,10 @@
import { ApplicationCommandType, ChatInputCommandInteraction, APIApplicationCommandOption, ApplicationCommandOptionType, APIEmbedField } from "discord.js"; import { ApplicationCommandType, ChatInputCommandInteraction, APIApplicationCommandOption, ApplicationCommandOptionType, APIEmbedField } from "discord.js";
import Command from "../command"; import
Command
,{ApplicationIntegrationType
, InteractionContextTypes
} from "../command";
import { config } from "../index"; import { config } from "../index";
export default class MyLimit extends Command implements Command { export default class MyLimit extends Command implements Command {
@ -21,6 +25,15 @@ export default class MyLimit extends Command implements Command {
required: false, required: false,
} }
]; ];
integration_types = [
ApplicationIntegrationType.Guild_Install,
ApplicationIntegrationType.User_Install
];
contexts = [
InteractionContextTypes.Guild,
InteractionContextTypes.BotDM,
InteractionContextTypes.PrivateChannel
];
async execute(interaction: ChatInputCommandInteraction) { async execute(interaction: ChatInputCommandInteraction) {
let recoveryFor = interaction.options.getInteger("recovery-for", false); let recoveryFor = interaction.options.getInteger("recovery-for", false);

26
src/commands/listen.ts Normal file
View file

@ -0,0 +1,26 @@
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,
});
}
}

View file

@ -1,4 +1,8 @@
import { Message } from "discord.js"; import {
ActivityType
, type PresenceStatusData
, type PresenceData
} from "discord.js";
import { import {
ChatCompletionMessageParam as OpenAIMessage, ChatCompletionMessageParam as OpenAIMessage,
ChatCompletionCreateParamsNonStreaming as ChatCompletionRequestData, ChatCompletionCreateParamsNonStreaming as ChatCompletionRequestData,
@ -6,18 +10,20 @@ import {
import IQuota from "./IQuota"; import IQuota from "./IQuota";
import MessageCount from "./quota/messageCount"; import MessageCount from "./quota/messageCount";
import { apiRequest } from "./execution";
export interface IConfigRequired { export interface IConfigRequired {
readonly calendarParams: Intl.DateTimeFormatOptions;
/** Tokens to authentiate with */ /** Tokens to authentiate with */
readonly tokens: { readonly tokens: {
readonly Discord: string; readonly Discord: string;
readonly OpenAI: string; readonly OpenAI: string;
}; };
/** Discord bot status */
readonly status: PresenceData
/** Messages to append at the start of every chat history when sending to API */ /** Messages to append at the start of every chat history when sending to API */
systemPrompt(context: Message): OpenAIMessage[]; systemPrompt(context: apiRequest): OpenAIMessage[];
/** OpenAI model config */ /** OpenAI model config */
readonly chatCompletionParams: Omit<ChatCompletionRequestData, "messages" | "function_call" | "functions" | "n">; readonly chatCompletionParams: Omit<ChatCompletionRequestData, "messages" | "function_call" | "tool_call" | "functions" | "n">;
/** Limits for message selection */ /** Limits for message selection */
readonly readLimits: { readonly readLimits: {
/** Maximum message age to include (in miliseconds) */ /** Maximum message age to include (in miliseconds) */
@ -40,6 +46,10 @@ export default function newConfig(config?: IConfig): IConfigRequired {
return { ...defaultConfig, ...config }; return { ...defaultConfig, ...config };
} }
function isEnvDefined(key: string): boolean {
return process.env[key] !== undefined;
}
function envAsString(key: string): string | undefined { function envAsString(key: string): string | undefined {
key = key.toLocaleUpperCase(); key = key.toLocaleUpperCase();
return process.env[key]; return process.env[key];
@ -51,16 +61,54 @@ function envAsNumber(key: string): number | undefined {
return !Number.isNaN(value) ? value : 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 = { const defaultConfig: IConfigRequired = {
calendarParams: {
weekday: "short",
year: "numeric",
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
hour12: false,
},
tokens: { tokens: {
Discord: envAsString("TOKENS__DISCORD") ?? "", Discord: envAsString("TOKENS__DISCORD") ?? "",
OpenAI: envAsString("TOKENS__OPENAI") ?? "", OpenAI: envAsString("TOKENS__OPENAI") ?? "",
@ -75,6 +123,16 @@ 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: { chatCompletionParams: {
model: envAsString("CHAT_COMPLETION_PARAMS__MODEL") ?? "gpt-3.5-turbo", model: envAsString("CHAT_COMPLETION_PARAMS__MODEL") ?? "gpt-3.5-turbo",
max_tokens: envAsNumber("CHAT_COMPLETION_PARAMS__MAX_TOKENS") ?? 384, max_tokens: envAsNumber("CHAT_COMPLETION_PARAMS__MAX_TOKENS") ?? 384,

View file

@ -73,7 +73,7 @@ export function getAuthor(request: apiRequest) {
* @returns Promise of the done action * @returns Promise of the done action
*/ */
function requestReply( function requestReply(
request: RequestMessage, request: apiRequest,
message: DiscordApi.MessageReplyOptions & DiscordApi.InteractionReplyOptions, message: DiscordApi.MessageReplyOptions & DiscordApi.InteractionReplyOptions,
// TODO: add support for these below // TODO: add support for these below
replyOptions: DiscordApi.MessageReplyOptions = {}, replyOptions: DiscordApi.MessageReplyOptions = {},
@ -172,29 +172,42 @@ export async function queueRequest(request: apiRequest) {
* Logs used tokens to the terminal and to the database * Logs used tokens to the terminal and to the database
* @param answer the response that OpenAI returned * @param answer the response that OpenAI returned
* @param message the message that initiated the execution * @param message the message that initiated the execution
* @param functionRan counter of how many function have been ran * @param functionRan counter of how many function have been ran (to distinct records in database)
*/ */
function logUsedTokens( function logUsedTokens(
answer: ChatCompletion, answer: ChatCompletion,
message: RequestMessage, message: apiRequest | undefined = undefined,
functionRan: number, functionRan: number = 0,
) { ) {
const usage = answer.usage; const usage = answer.usage;
const functionName = answer.choices[0].message?.function_call?.name; const functionNames =
answer.choices[0].message.tool_calls?.map(
v => v.type === "function" ? v.function.name : `[unknown type]`
);
if (usage !== undefined) { if (usage !== undefined) {
const channelName: string = !message.channel.isDMBased() ? `${message.channel.name} (${message.guild?.name})` : `@${getAuthor(message).tag}`; if (!message) {
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 + "]" : ""}`); // 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(", ") + "]" : ""}`);
database.usage.create({ database.usage.create({
data: { data: {
timestamp: message.createdAt, timestamp: message.createdAt,
user: BigInt(getAuthor(message).id), user: BigInt(getAuthor(message).id),
channel: BigInt(message.channelId), channel: BigInt(message.channelId ?? 0),
guild: message.guildId ? BigInt(message.guildId) : null, guild: message.guildId ? BigInt(message.guildId) : null,
usageRequest: usage.prompt_tokens, usageRequest: usage.prompt_tokens,
usageResponse: usage.completion_tokens, usageResponse: usage.completion_tokens,
functionName: functionName ?? null, functionName: functionNames?.join(", ") ?? null,
functionRan: functionName ? functionRan : 0, functionRan: functionRan,
} }
}).catch((e => { }).catch((e => {
console.error("Failed to push to a database"); console.error("Failed to push to a database");
@ -210,7 +223,6 @@ function logUsedTokens(
async function executeFromQueue(channel: string) { async function executeFromQueue(channel: string) {
const channelQueue = channelsRunning.get(channel) as ChannelsRunningValue; const channelQueue = channelsRunning.get(channel) as ChannelsRunningValue;
const message = channelQueue.at(0) as RequestMessage; const message = channelQueue.at(0) as RequestMessage;
let functionRanCounter = 0;
let OpenAImessages: ChatCompletionMessageParam[] = []; let OpenAImessages: ChatCompletionMessageParam[] = [];
// ignore if we can't even send anything to reply // ignore if we can't even send anything to reply
@ -238,56 +250,13 @@ async function executeFromQueue(channel: string) {
}); });
OpenAImessages = toOpenAIMessages(messages.values()); OpenAImessages = toOpenAIMessages(messages.values());
let generatedMessage: ChatCompletionMessage | undefined = undefined; const answer = await executeChatCompletion(OpenAImessages, message);
let answer: Awaited<ReturnType<typeof openai.chat.completions.create>>;
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)
);
}
} while (generatedMessage.function_call);
channelQueue.stopTyping(); channelQueue.stopTyping();
const answerContent = answer.choices[0].message?.content; const answerContent = answer.choices[0].message?.content;
if (answerContent === null || answerContent === "") { await replyInMultiMessage(answerContent, message);
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) { } catch (e) {
let errorText: string = ""; let errorText: string = "";
channelQueue.stopTyping(); channelQueue.stopTyping();
@ -341,3 +310,70 @@ async function executeFromQueue(channel: string) {
else else
return executeFromQueue(channel); 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<ReturnType<typeof openai.chat.completions.create>>;
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;
}

View file

@ -1,49 +1,43 @@
import { ChatCompletionCreateParams, ChatCompletionMessage, ChatCompletionMessageParam } from "openai/resources/chat"; import { FunctionDefinition } from "openai/resources";
import {
ChatCompletionMessageParam
, ChatCompletionMessageToolCall
, ChatCompletionTool
} from "openai/resources/chat";
import { type FromSchema, type JSONSchema } from "json-schema-to-ts";
import { config } from "./index"; type OpenAIFunctionRequestData = (JSONSchema & {
type: "object"
});
type parameterMap = { type ChatCompletionToolDefinition = ChatCompletionTool;
string: string, type ChatCompletionToolCall = ChatCompletionMessageToolCall;
number: number,
};
type nameTypeMap = {[name: string]: keyof parameterMap} | Record<string, never>; type ChatCompletionFunctionDefinition = FunctionDefinition;
type OpenAIFunctionRequestData<T extends nameTypeMap> = {
[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 * Represents the function that can be ran by the OpenAI model
*/ */
export interface OpenAIFunction<T extends nameTypeMap = nameTypeMap> { export interface OpenAIFunction<
T extends Readonly<OpenAIFunctionRequestData> = Readonly<OpenAIFunctionRequestData>
> {
name: string, name: string,
description?: string, description?: string,
parameters: { parameters: T,
type: "object",
properties: T extends Record<string, never> ? Record<string, never> : {
[name in T[string]]: {
type: T[name],
description?: string,
}
},
required?: Array<keyof T>,
},
} }
export abstract class OpenAIFunction<T extends nameTypeMap = nameTypeMap> { export abstract class OpenAIFunction<
getSettings(): ChatCompletionFunctions { T extends Readonly<OpenAIFunctionRequestData> = Readonly<OpenAIFunctionRequestData>
> {
getSettings(): ChatCompletionFunctionDefinition {
return { return {
name: this.name, name: this.name,
description: this.description, description: this.description,
parameters: this.parameters, parameters: this.parameters as Record<string, unknown>,
}; };
} }
abstract execute(data: OpenAIFunctionRequestData<T>): string; abstract execute(data: FromSchema<T>): Promise<string>;
} }
/* /*
@ -53,60 +47,70 @@ export default class FunctionManager {
store = new Map<string, OpenAIFunction>(); store = new Map<string, OpenAIFunction>();
constructor() { constructor() {
this.store.set("getTime", new GetTime()); // TODO: import functions from functions directory
} }
public getFunctions(): ChatCompletionFunctions[] { public getTools(): ChatCompletionToolDefinition[] {
const rvalue: ChatCompletionFunctions[] = []; const rvalue: ChatCompletionToolDefinition[] = [];
for (const [, value] of this.store) { for (const [, value] of this.store) {
rvalue.push(value.getSettings()); rvalue.push({type: "function", function: value.getSettings()});
} }
return rvalue; return rvalue;
} }
public handleFunction(request: ChatCompletionFunctionCall): ChatCompletionMessageParam { public getToolsForOpenAi(): ChatCompletionTool[] | undefined {
const rvalue = this.getTools();
return rvalue.length > 0 ? rvalue : undefined;
}
public handleFunction(request: ChatCompletionToolCall): Promise<ChatCompletionMessageParam> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
let parsedArguments: any; let parsedArguments: any;
const functionToRun = this.store.get(request.name ?? ""); const functionToRun = this.store.get(request.function.name);
// check if the function is registered // check if the function is registered
if (!functionToRun) { if (!functionToRun) {
return { return Promise.resolve({
role: "system", role: "system",
content: "Only use functions that were provided to you", content: `Only use functions that were provided to you (response for tool call ID: ${request.id})`,
}; });
} }
try { try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
parsedArguments = JSON.parse(request.arguments ?? ""); parsedArguments = JSON.parse(request.function.arguments);
} }
catch (e) { catch (e) {
console.error("Function arguments raw: " + request.arguments); console.error("Function arguments raw: " + request.function.arguments);
throw new Error(`Failed to parse the function JSON arguments when running function [${request.name}]`, {cause: e}); throw new Error(`Failed to parse the function JSON arguments when running function [${request.function.name}]`, {cause: e});
} }
// FIXME: Verify if the parsedArguments matches the requested function argument declaration. // FIXME: Verify if the parsedArguments matches the requested function argument declaration.
return {
role: "function",
name: request.name,
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
content: functionToRun.execute(parsedArguments), return functionToRun.execute(parsedArguments).then(content => {
return {
role: "tool",
tool_call_id: request.id,
content: content,
}; };
} });
} }
// buildins public handleToolCall(call: ChatCompletionToolCall): Promise<ChatCompletionMessageParam> {
if (call.type === "function") {
class GetTime extends OpenAIFunction<Record<string, never>> { return this.handleFunction(call);
name = "getTime"; }
description = "Gets current date and time with a timezone attached"; // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
parameters = { throw new Error(`Unsupported tool call type: ${call.type || "never"}`);
type: "object" as const, }
properties: {} as Record<string, never>,
}; public handleToolCalls(calls: ChatCompletionToolCall[]) {
const rvalue: Promise<ChatCompletionMessageParam>[] = [];
execute(): string { for (const call of calls) {
return `${Intl.DateTimeFormat().resolvedOptions().timeZone}): ${new Date().toLocaleString("en-US", config.calendarParams)}`; if (call.type === "function") {
rvalue.push(this.handleToolCall(call));
}
}
return Promise.all(rvalue);
} }
} }

View file

@ -11,6 +11,7 @@ const discord = new DiscordApi.Client({
intents: [ intents: [
DiscordApi.GatewayIntentBits.Guilds, DiscordApi.GatewayIntentBits.Guilds,
DiscordApi.GatewayIntentBits.GuildMessages, DiscordApi.GatewayIntentBits.GuildMessages,
DiscordApi.GatewayIntentBits.DirectMessages,
DiscordApi.GatewayIntentBits.MessageContent, DiscordApi.GatewayIntentBits.MessageContent,
] ]
}); });
@ -54,13 +55,29 @@ interactionManager.bindClient(discord);
discord.on("ready", event => { discord.on("ready", event => {
console.log(`Connected to Discord as ${event.user.tag} (${event.user.id})`); console.log(`Connected to Discord as ${event.user.tag} (${event.user.id})`);
event.user.setPresence(config.status);
}); });
discord.on("messageCreate", message => { discord.on("messageCreate", message => {
if (message.author.bot) return; if (message.author.bot) return;
if (!message.mentions.has(message.client.user)) return; if (!message.channel.isDMBased()) {
if (!message.mentions.has(message.client.user, { ignoreEveryone: true })) return;
}
return queueRequest(message); return queueRequest(message);
}); });
if (require.main === module) void discord.login(config.tokens.Discord); 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();
});
});
}

View file

@ -63,7 +63,7 @@ export function formatMessage(message: DiscordMessage): string {
* @param name the name to format * @param name the name to format
* @returns formatted name * @returns formatted name
*/ */
function formatName(name: string): string { export function formatName(name: string): string {
// replace all characters to ascii equivelant // replace all characters to ascii equivelant
return FoldToAscii.foldReplacing(name) return FoldToAscii.foldReplacing(name)
// White spaces are not allowed // White spaces are not allowed