mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-22 02:03:42 +00:00
fix(mom): private channel messages not being logged
- Add message.groups to required bot events in README - Add groups:history and groups:read to required scopes in README - app_mention handler now logs messages directly instead of relying on message event - Add deduplication in ChannelStore.logMessage() to prevent double-logging - Remove redundant current message append in agent.ts (already in log)
This commit is contained in:
parent
db6d655ee9
commit
706554a5d3
6 changed files with 67 additions and 11 deletions
|
|
@ -2,6 +2,14 @@
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Private channel messages not being logged
|
||||||
|
- Added `message.groups` to required bot events in README
|
||||||
|
- Added `groups:history` and `groups:read` to required scopes in README
|
||||||
|
- `app_mention` handler now logs messages directly instead of relying on `message` event
|
||||||
|
- Added deduplication in `ChannelStore.logMessage()` to prevent double-logging
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Message backfill on startup (#103)
|
- Message backfill on startup (#103)
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@ npm install @mariozechner/pi-mom
|
||||||
- `chat:write`
|
- `chat:write`
|
||||||
- `files:read`
|
- `files:read`
|
||||||
- `files:write`
|
- `files:write`
|
||||||
|
- `groups:history`
|
||||||
|
- `groups:read`
|
||||||
- `im:history`
|
- `im:history`
|
||||||
- `im:read`
|
- `im:read`
|
||||||
- `im:write`
|
- `im:write`
|
||||||
|
|
@ -38,6 +40,7 @@ npm install @mariozechner/pi-mom
|
||||||
5. **Subscribe to Bot Events** (Event Subscriptions):
|
5. **Subscribe to Bot Events** (Event Subscriptions):
|
||||||
- `app_mention`
|
- `app_mention`
|
||||||
- `message.channels`
|
- `message.channels`
|
||||||
|
- `message.groups`
|
||||||
- `message.im`
|
- `message.im`
|
||||||
6. Install the app to your workspace. Get the **Bot User OAuth Token**. This is `MOM_SLACK_BOT_TOKEN`
|
6. Install the app to your workspace. Get the **Bot User OAuth Token**. This is `MOM_SLACK_BOT_TOKEN`
|
||||||
7. Add mom to any channels where you want her to operate (she'll only see messages in channels she's added to)
|
7. Add mom to any channels where you want her to operate (she'll only see messages in channels she's added to)
|
||||||
|
|
|
||||||
30
packages/mom/dev.sh
Executable file
30
packages/mom/dev.sh
Executable file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CONTAINER_NAME="mom-sandbox"
|
||||||
|
DATA_DIR="$(pwd)/data"
|
||||||
|
|
||||||
|
# Create data directory if it doesn't exist
|
||||||
|
mkdir -p "$DATA_DIR"
|
||||||
|
|
||||||
|
# Check if container exists
|
||||||
|
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
||||||
|
# Check if it's running
|
||||||
|
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
||||||
|
echo "Starting existing container: $CONTAINER_NAME"
|
||||||
|
docker start "$CONTAINER_NAME"
|
||||||
|
else
|
||||||
|
echo "Container $CONTAINER_NAME already running"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Creating container: $CONTAINER_NAME"
|
||||||
|
docker run -d \
|
||||||
|
--name "$CONTAINER_NAME" \
|
||||||
|
-v "$DATA_DIR:/workspace" \
|
||||||
|
alpine:latest \
|
||||||
|
tail -f /dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run mom with tsx watch mode
|
||||||
|
echo "Starting mom in dev mode..."
|
||||||
|
npx tsx --watch-path src --watch src/main.ts --sandbox=docker:$CONTAINER_NAME ./data
|
||||||
|
|
@ -364,15 +364,7 @@ export function createAgentRunner(sandboxConfig: SandboxConfig): AgentRunner {
|
||||||
|
|
||||||
const channelId = ctx.message.channel;
|
const channelId = ctx.message.channel;
|
||||||
const workspacePath = executor.getWorkspacePath(channelDir.replace(`/${channelId}`, ""));
|
const workspacePath = executor.getWorkspacePath(channelDir.replace(`/${channelId}`, ""));
|
||||||
const recentMessagesFromLog = getRecentMessages(channelDir, 50);
|
const recentMessages = getRecentMessages(channelDir, 50);
|
||||||
|
|
||||||
// Append the current message (may not be in log yet due to race condition
|
|
||||||
// between app_mention and message events)
|
|
||||||
const currentMsgDate = new Date(parseFloat(ctx.message.ts) * 1000).toISOString().substring(0, 19);
|
|
||||||
const currentMsgUser = ctx.message.userName || ctx.message.user;
|
|
||||||
const currentMsgAttachments = ctx.message.attachments.map((a) => a.local).join(",");
|
|
||||||
const currentMsgLine = `${currentMsgDate}\t${currentMsgUser}\t${ctx.message.rawText}\t${currentMsgAttachments}`;
|
|
||||||
const recentMessages = recentMessagesFromLog + "\n" + currentMsgLine;
|
|
||||||
|
|
||||||
const memory = getMemory(channelDir);
|
const memory = getMemory(channelDir);
|
||||||
const systemPrompt = buildSystemPrompt(
|
const systemPrompt = buildSystemPrompt(
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,6 @@ export class MomBot {
|
||||||
|
|
||||||
private setupEventHandlers(): void {
|
private setupEventHandlers(): void {
|
||||||
// Handle @mentions in channels
|
// Handle @mentions in channels
|
||||||
// Note: We don't log here - the message event handler logs all messages
|
|
||||||
this.socketClient.on("app_mention", async ({ event, ack }) => {
|
this.socketClient.on("app_mention", async ({ event, ack }) => {
|
||||||
await ack();
|
await ack();
|
||||||
|
|
||||||
|
|
@ -220,6 +219,15 @@ export class MomBot {
|
||||||
files?: Array<{ name: string; url_private_download?: string; url_private?: string }>;
|
files?: Array<{ name: string; url_private_download?: string; url_private?: string }>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Log the mention message (message event may not fire for all channel types)
|
||||||
|
await this.logMessage({
|
||||||
|
text: slackEvent.text,
|
||||||
|
channel: slackEvent.channel,
|
||||||
|
user: slackEvent.user,
|
||||||
|
ts: slackEvent.ts,
|
||||||
|
files: slackEvent.files,
|
||||||
|
});
|
||||||
|
|
||||||
const ctx = await this.createContext(slackEvent);
|
const ctx = await this.createContext(slackEvent);
|
||||||
await this.handler.onChannelMention(ctx);
|
await this.handler.onChannelMention(ctx);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,9 @@ export class ChannelStore {
|
||||||
private botToken: string;
|
private botToken: string;
|
||||||
private pendingDownloads: PendingDownload[] = [];
|
private pendingDownloads: PendingDownload[] = [];
|
||||||
private isDownloading = false;
|
private isDownloading = false;
|
||||||
|
// Track recently logged message timestamps to prevent duplicates
|
||||||
|
// Key: "channelId:ts", automatically cleaned up after 60 seconds
|
||||||
|
private recentlyLogged = new Map<string, number>();
|
||||||
|
|
||||||
constructor(config: ChannelStoreConfig) {
|
constructor(config: ChannelStoreConfig) {
|
||||||
this.workingDir = config.workingDir;
|
this.workingDir = config.workingDir;
|
||||||
|
|
@ -107,8 +110,19 @@ export class ChannelStore {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log a message to the channel's log.jsonl
|
* Log a message to the channel's log.jsonl
|
||||||
|
* Returns false if message was already logged (duplicate)
|
||||||
*/
|
*/
|
||||||
async logMessage(channelId: string, message: LoggedMessage): Promise<void> {
|
async logMessage(channelId: string, message: LoggedMessage): Promise<boolean> {
|
||||||
|
// Check for duplicate (same channel + timestamp)
|
||||||
|
const dedupeKey = `${channelId}:${message.ts}`;
|
||||||
|
if (this.recentlyLogged.has(dedupeKey)) {
|
||||||
|
return false; // Already logged
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark as logged and schedule cleanup after 60 seconds
|
||||||
|
this.recentlyLogged.set(dedupeKey, Date.now());
|
||||||
|
setTimeout(() => this.recentlyLogged.delete(dedupeKey), 60000);
|
||||||
|
|
||||||
const logPath = join(this.getChannelDir(channelId), "log.jsonl");
|
const logPath = join(this.getChannelDir(channelId), "log.jsonl");
|
||||||
|
|
||||||
// Ensure message has a date field
|
// Ensure message has a date field
|
||||||
|
|
@ -127,6 +141,7 @@ export class ChannelStore {
|
||||||
|
|
||||||
const line = JSON.stringify(message) + "\n";
|
const line = JSON.stringify(message) + "\n";
|
||||||
await appendFile(logPath, line, "utf-8");
|
await appendFile(logPath, line, "utf-8");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue