Skip to content

Commit

Permalink
handle message permissions better
Browse files Browse the repository at this point in the history
  • Loading branch information
lalalune committed Nov 4, 2024
1 parent 9f6ac99 commit f8b42df
Showing 1 changed file with 119 additions and 67 deletions.
186 changes: 119 additions & 67 deletions core/src/clients/discord/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import {
ChannelType,
Client,
Message as DiscordMessage,
PermissionsBitField,
TextChannel,
ThreadChannel,
} from "discord.js";
import { composeContext } from "../../core/context.ts";
import {
Expand All @@ -27,6 +29,7 @@ import { AttachmentManager } from "./attachments.ts";
import { messageHandlerTemplate, shouldRespondTemplate } from "./templates.ts";
import { InterestChannels } from "./types.ts";
import { VoiceManager } from "./voice.ts";
import { prettyConsole } from "../../index.ts";

const MAX_MESSAGE_LENGTH = 1900;

Expand Down Expand Up @@ -102,6 +105,52 @@ function splitMessage(content: string): string[] {
return messages;
}


function canSendMessage(channel) {
// Get the bot member in the guild
const botMember = channel.guild?.members.cache.get(channel.client.user.id);

if (!botMember) {
return {
canSend: false,
reason: 'Not a guild channel or bot member not found'
};
}

// Required permissions for sending messages
const requiredPermissions = [
PermissionsBitField.Flags.ViewChannel,
PermissionsBitField.Flags.SendMessages,
PermissionsBitField.Flags.ReadMessageHistory
];

// Add thread-specific permission if it's a thread
if (channel instanceof ThreadChannel) {
requiredPermissions.push(PermissionsBitField.Flags.SendMessagesInThreads);
}

// Check permissions
const permissions = channel.permissionsFor(botMember);

if (!permissions) {
return {
canSend: false,
reason: 'Could not retrieve permissions'
};
}

// Check each required permission
const missingPermissions = requiredPermissions.filter(perm => !permissions.has(perm));

return {
canSend: missingPermissions.length === 0,
missingPermissions: missingPermissions,
reason: missingPermissions.length > 0
? `Missing permissions: ${missingPermissions.map(p => String(p)).join(', ')}`
: null
};
}

export class MessageManager {
private client: Client;
private runtime: IAgentRuntime;
Expand All @@ -122,7 +171,7 @@ export class MessageManager {
if (
message.interaction ||
message.author.id ===
this.client.user?.id /* || message.author?.bot*/
this.client.user?.id /* || message.author?.bot*/
)
return;
const userId = message.author.id as UUID;
Expand Down Expand Up @@ -178,14 +227,6 @@ export class MessageManager {
roomId,
};

let state = (await this.runtime.composeState(userMessage, {
discordClient: this.client,
discordMessage: message,
agentName:
this.runtime.character.name ||
this.client.user?.displayName,
})) as State;

const memory: Memory = {
id: stringToUuid(message.id + "-" + this.runtime.agentId),
...userMessage,
Expand All @@ -201,7 +242,18 @@ export class MessageManager {
await this.runtime.messageManager.createMemory(memory);
}

state = await this.runtime.updateRecentMessageState(state);
let state = (await this.runtime.composeState(userMessage, {
discordClient: this.client,
discordMessage: message,
agentName:
this.runtime.character.name ||
this.client.user?.displayName,
})) as State;

if (!canSendMessage(message.channel).canSend) {
return prettyConsole.warn(`Cannot send message to channel ${message.channel}`, canSendMessage(message.channel));
}


if (!shouldIgnore) {
shouldIgnore = await this._shouldIgnore(message);
Expand Down Expand Up @@ -267,70 +319,70 @@ export class MessageManager {
files: any[]
) => {
try {
if (message.id && !content.inReplyTo) {
content.inReplyTo = stringToUuid(message.id + "-" + this.runtime.agentId);
}
if (message.channel.type === ChannelType.GuildVoice) {
// For voice channels, use text-to-speech
const audioStream =
await this.runtime.speechService.generate(
this.runtime,
content.text
if (message.id && !content.inReplyTo) {
content.inReplyTo = stringToUuid(message.id + "-" + this.runtime.agentId);
}
if (message.channel.type === ChannelType.GuildVoice) {
// For voice channels, use text-to-speech
const audioStream =
await this.runtime.speechService.generate(
this.runtime,
content.text
);
await this.voiceManager.playAudioStream(
userId,
audioStream
);
await this.voiceManager.playAudioStream(
userId,
audioStream
);
const memory: Memory = {
id: stringToUuid(message.id + "-" + this.runtime.agentId),
userId: this.runtime.agentId,
agentId: this.runtime.agentId,
content,
roomId,
embedding: embeddingZeroVector,
};
return [memory];
} else {
// For text channels, send the message
const messages = await sendMessageInChunks(
message.channel as TextChannel,
content.text,
message.id,
files
);

const memories: Memory[] = [];
for (const m of messages) {
let action = content.action;
// If there's only one message or it's the last message, keep the original action
// For multiple messages, set all but the last to 'CONTINUE'
if (
messages.length > 1 &&
m !== messages[messages.length - 1]
) {
action = "CONTINUE";
}

const memory: Memory = {
id: stringToUuid(m.id + "-" + this.runtime.agentId),
id: stringToUuid(message.id + "-" + this.runtime.agentId),
userId: this.runtime.agentId,
agentId: this.runtime.agentId,
content: {
...content,
action,
inReplyTo: messageId,
url: m.url,
},
content,
roomId,
embedding: embeddingZeroVector,
createdAt: m.createdTimestamp,
};
memories.push(memory);
}
for (const m of memories) {
await this.runtime.messageManager.createMemory(m);
}
return memories;
return [memory];
} else {
// For text channels, send the message
const messages = await sendMessageInChunks(
message.channel as TextChannel,
content.text,
message.id,
files
);

const memories: Memory[] = [];
for (const m of messages) {
let action = content.action;
// If there's only one message or it's the last message, keep the original action
// For multiple messages, set all but the last to 'CONTINUE'
if (
messages.length > 1 &&
m !== messages[messages.length - 1]
) {
action = "CONTINUE";
}

const memory: Memory = {
id: stringToUuid(m.id + "-" + this.runtime.agentId),
userId: this.runtime.agentId,
agentId: this.runtime.agentId,
content: {
...content,
action,
inReplyTo: messageId,
url: m.url,
},
roomId,
embedding: embeddingZeroVector,
createdAt: m.createdTimestamp,
};
memories.push(memory);
}
for (const m of memories) {
await this.runtime.messageManager.createMemory(m);
}
return memories;
}
} catch (error) {
console.error("Error sending message:", error);
Expand Down

0 comments on commit f8b42df

Please sign in to comment.