Update eslintrc.json to also make it consider typings

note that I've marked Promises awaiting as a warn,
because I don't want to be bothered with it for now.

I also edited all files to accomodate with the new rules.

I should also think find a way to type-safely import Commands directory,
another time
This commit is contained in:
Wroclaw 2023-07-30 22:28:13 +02:00
parent c4676175ff
commit 7225739527
9 changed files with 35 additions and 23 deletions

View file

@ -1,8 +1,15 @@
{ {
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended-type-checked"],
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"rules": { "rules": {
"@typescript-eslint/no-floating-promises": "warn",
"@typescript-eslint/no-unsafe-declaration-merging": "warn",
"@typescript-eslint/semi": ["error", "always"], "@typescript-eslint/semi": ["error", "always"],
"eol-last": ["error", "always"] "semi": "off",
"eol-last": ["error", "always"],
"eqeqeq": ["error", "always"]
} }
} }

View file

@ -10,7 +10,7 @@ export default class Summon extends Command {
type = ApplicationCommandType.ChatInput; type = ApplicationCommandType.ChatInput;
dm_permission = false; dm_permission = false;
async execute(interaction: ChatInputCommandInteraction) { execute(interaction: ChatInputCommandInteraction) {
queueRequest(interaction); return queueRequest(interaction);
} }
} }

View file

@ -134,9 +134,9 @@ function canReplyToRequest(request: apiRequest) {
export async function queueRequest(request: apiRequest) { export async function queueRequest(request: apiRequest) {
if (!request.channelId) { if (!request.channelId) {
if (request instanceof DiscordApi.Message) if (request instanceof DiscordApi.Message)
request.reply("request does not have channelId"); await request.reply("request does not have channelId");
else if (request.isRepliable()) else if (request.isRepliable())
request.reply("request does not have channelId"); await request.reply("request does not have channelId");
console.log("There was incoming execution without channelId set, ignoring"); console.log("There was incoming execution without channelId set, ignoring");
console.log(request); console.log(request);
return; return;
@ -148,7 +148,7 @@ export async function queueRequest(request: apiRequest) {
if (userLimit !== false && userLimit.remaining <= 0) { if (userLimit !== false && userLimit.remaining <= 0) {
if (request instanceof DiscordApi.Message) { if (request instanceof DiscordApi.Message) {
request.react("🛑").catch(/*it's okay*/); request.react("🛑").catch(() => { /* NOTE: We send an informaton about limit reached in DM */ });
if (!request.author.dmChannel) await request.author.createDM(); if (!request.author.dmChannel) await request.author.createDM();
request.author.dmChannel?.send({ request.author.dmChannel?.send({
embeds: [{ embeds: [{
@ -157,13 +157,13 @@ export async function queueRequest(request: apiRequest) {
"You've used up your message limit for today,\n" + "You've used up your message limit for today,\n" +
`${userLimit.limit} requests in last 24 hours`, `${userLimit.limit} requests in last 24 hours`,
}] }]
}); }).catch(() => {/* GRACEFAIL: */});
} }
else if (request.isRepliable()) { else if (request.isRepliable()) {
request.reply({ request.reply({
content: `You've used up your message limit for today, ${userLimit.limit} requests in last 24 hours`, content: `You've used up your message limit for today, ${userLimit.limit} requests in last 24 hours`,
ephemeral: true, ephemeral: true,
}); }).catch(() => { /* Impossible to get there unless connection lost*/ });
} }
return; return;
} }
@ -172,7 +172,7 @@ export async function queueRequest(request: apiRequest) {
request.channelId, request.channelId,
() => { return []; }, () => { return []; },
); );
const shouldStart = messagesForChannel.length == 0; const shouldStart = messagesForChannel.length === 0;
messagesForChannel.push(request as request); messagesForChannel.push(request as request);
if (shouldStart) if (shouldStart)
executeFromQueue(request.channelId); executeFromQueue(request.channelId);
@ -191,7 +191,7 @@ function logUsedTokens(
) { ) {
const usage = answer.data.usage; const usage = answer.data.usage;
const functionName = answer.data.choices[0].message?.function_call?.name; const functionName = answer.data.choices[0].message?.function_call?.name;
if (usage != undefined) { if (usage !== undefined) {
const channelName: string = !message.channel.isDMBased() ? `${message.channel.name} (${message.guild?.name})` : `@${getAuthor(message).tag}`; 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 + "]" : ""}`); 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 + "]" : ""}`);
@ -231,7 +231,7 @@ async function executeFromQueue(channel: string) {
messages = messages.filter(m => message.createdTimestamp - m.createdTimestamp < config.limits.time ); messages = messages.filter(m => message.createdTimestamp - m.createdTimestamp < config.limits.time );
messages.forEach(m => Moderation.checkMessage(m)); messages.forEach(m => { Moderation.checkMessage(m); });
if (message instanceof DiscordApi.Message) { if (message instanceof DiscordApi.Message) {
message.channel.sendTyping(); message.channel.sendTyping();
@ -269,7 +269,7 @@ async function executeFromQueue(channel: string) {
const answerContent = answer.data.choices[0].message?.content; const answerContent = answer.data.choices[0].message?.content;
if (answerContent == undefined || answerContent == "") { if (answerContent === undefined || answerContent === "") {
if (message instanceof DiscordApi.Message) message.react("😶").catch(/*it's okay*/); if (message instanceof DiscordApi.Message) message.react("😶").catch(/*it's okay*/);
} }
else { else {
@ -293,7 +293,7 @@ async function executeFromQueue(channel: string) {
} catch (e) { } catch (e) {
console.error(`Error ocurred while handling chat completion request (${(e as object).constructor.name}):`); console.error(`Error ocurred while handling chat completion request (${(e as object).constructor.name}):`);
console.error(e); console.error(e);
if (OpenAImessages.length != 0) { if (OpenAImessages.length !== 0) {
console.error("Messages:"); console.error("Messages:");
console.error(OpenAImessages); console.error(OpenAImessages);
} }
@ -319,7 +319,7 @@ async function executeFromQueue(channel: string) {
} }
channelQueue.shift(); channelQueue.shift();
if (channelQueue.length == 0) if (channelQueue.length === 0)
channelsRunning.delete(channel); channelsRunning.delete(channel);
else else
executeFromQueue(channel); executeFromQueue(channel);

View file

@ -76,15 +76,18 @@ export default class FunctionManager {
} }
try { try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
parsedArguments = JSON.parse(request.arguments ?? ""); parsedArguments = JSON.parse(request.arguments ?? "");
} }
catch (e) { catch (e) {
console.error("Function arguments raw: " + request.arguments); console.error("Function arguments raw: " + request.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.name}]`, {cause: e});
} }
// FIXME: Verify if the parsedArguments matches the requested function argument declaration.
return { return {
role: "function", role: "function",
name: request.name, name: request.name,
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
content: functionToRun.execute(parsedArguments), content: functionToRun.execute(parsedArguments),
}; };
} }

View file

@ -23,11 +23,11 @@ export const database = new PrismaClient();
const interactionManager = new InteractionManager(); const interactionManager = new InteractionManager();
interactionManager.bindClient(discord); interactionManager.bindClient(discord);
discord.on("ready", async 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})`);
}); });
discord.on("messageCreate", async 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.mentions.has(message.client.user)) return;

View file

@ -12,6 +12,7 @@ export default class CommandManager {
try { try {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
this.commands.push(new (files[i].default as Command)()); this.commands.push(new (files[i].default as Command)());
} }
catch (e) { catch (e) {
@ -27,13 +28,13 @@ export default class CommandManager {
interaction.isMessageContextMenuCommand() || interaction.isMessageContextMenuCommand() ||
interaction.isUserContextMenuCommand() interaction.isUserContextMenuCommand()
) { ) {
const foundCommand = this.commands.find((command) => command.name == interaction.commandName ); const foundCommand = this.commands.find((command) => command.name === interaction.commandName );
if (!foundCommand) throw new Error(`Unknown command received (${interaction.commandName}). Did you forgot to push updated commands?`); if (!foundCommand) throw new Error(`Unknown command received (${interaction.commandName}). Did you forgot to push updated commands?`);
foundCommand.execute(interaction); foundCommand.execute(interaction);
return; return;
} }
if (interaction.isAutocomplete()) { if (interaction.isAutocomplete()) {
const foundCommand = this.commands.find((command) => command.name == interaction.commandName ); const foundCommand = this.commands.find((command) => command.name === interaction.commandName );
if (!foundCommand) throw new Error(`Unknown command received (${interaction.commandName}). Did you forgot to push updated commands?`); if (!foundCommand) throw new Error(`Unknown command received (${interaction.commandName}). Did you forgot to push updated commands?`);
if (!foundCommand.autocomplete) return; if (!foundCommand.autocomplete) return;
foundCommand.autocomplete(interaction); foundCommand.autocomplete(interaction);

View file

@ -31,11 +31,11 @@ export default class Moderation {
const flagged = answer.data.results[0].flagged; const flagged = answer.data.results[0].flagged;
this.cache.set(message.id, flagged); this.cache.set(message.id, flagged);
if (flagged) if (message instanceof Message) { if (flagged) if (message instanceof Message) {
message.react("⚠"); message.react("⚠").catch(() => { /* GRACEFAIL: We don't inform the enduser then */ });
} }
else { else {
const channelMessage = await message.fetch(); const channelMessage = await message.fetch();
channelMessage.react("⚠"); channelMessage.react("⚠").catch(() => { /* GRACEFAIL: We don't inform the enduser then */ });
} }
return flagged; return flagged;

View file

@ -14,6 +14,7 @@ requireDirectory<{default: Command}, void>(module, "../commands", {
console.log(obj); console.log(obj);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
post.push(new obj.default().toRESTPostApplicationCommands()); post.push(new obj.default().toRESTPostApplicationCommands());
}, },
}); });
@ -22,7 +23,7 @@ const rest = new REST().setToken(config.tokens.Discord);
(async () => { (async () => {
const me = await rest.get(Routes.oauth2CurrentApplication()) as RESTGetAPIOAuth2CurrentApplicationResult; const me = await rest.get(Routes.oauth2CurrentApplication()) as RESTGetAPIOAuth2CurrentApplicationResult;
if (guildId && guildId != "") { if (guildId && guildId !== "") {
console.log(`Started refreshing ${post.length} application guild (${guildId}) commands.`); console.log(`Started refreshing ${post.length} application guild (${guildId}) commands.`);
await rest.put( await rest.put(
Routes.applicationGuildCommands(me.id, guildId), Routes.applicationGuildCommands(me.id, guildId),

View file

@ -108,7 +108,7 @@ export default function toOpenAIMessages(messages: Collection<string, DiscordMes
tokenCount += countTokens(content); tokenCount += countTokens(content);
if (tokenCount > config.limits.tokens) break; if (tokenCount > config.limits.tokens) break;
rvalue.push({ rvalue.push({
role: message.author.id == message.client.user.id ? "assistant" : "user", role: message.author.id === message.client.user.id ? "assistant" : "user",
content: content, content: content,
name: getAuthorUsername(message), name: getAuthorUsername(message),
}); });