@geminixiang/mama 0.2.0-beta.6 → 0.2.0-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -14
- package/dist/adapter.d.ts +5 -2
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js.map +1 -1
- package/dist/adapters/discord/bot.d.ts +1 -0
- package/dist/adapters/discord/bot.d.ts.map +1 -1
- package/dist/adapters/discord/bot.js +29 -9
- package/dist/adapters/discord/bot.js.map +1 -1
- package/dist/adapters/discord/context.d.ts +1 -1
- package/dist/adapters/discord/context.d.ts.map +1 -1
- package/dist/adapters/discord/context.js +1 -2
- package/dist/adapters/discord/context.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +8 -0
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +177 -11
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/branch-manager.d.ts +1 -0
- package/dist/adapters/slack/branch-manager.d.ts.map +1 -1
- package/dist/adapters/slack/branch-manager.js +9 -8
- package/dist/adapters/slack/branch-manager.js.map +1 -1
- package/dist/adapters/slack/context.d.ts +1 -1
- package/dist/adapters/slack/context.d.ts.map +1 -1
- package/dist/adapters/slack/context.js +10 -8
- package/dist/adapters/slack/context.js.map +1 -1
- package/dist/adapters/slack/tools/attach.d.ts +1 -1
- package/dist/adapters/slack/tools/attach.d.ts.map +1 -1
- package/dist/adapters/slack/tools/attach.js.map +1 -1
- package/dist/adapters/telegram/bot.d.ts.map +1 -1
- package/dist/adapters/telegram/bot.js +33 -2
- package/dist/adapters/telegram/bot.js.map +1 -1
- package/dist/agent.d.ts +1 -2
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +507 -422
- package/dist/agent.js.map +1 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +2 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +41 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/model.d.ts +1 -1
- package/dist/commands/model.d.ts.map +1 -1
- package/dist/commands/model.js +25 -7
- package/dist/commands/model.js.map +1 -1
- package/dist/commands/new.d.ts.map +1 -1
- package/dist/commands/new.js +1 -1
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/sandbox.d.ts +10 -0
- package/dist/commands/sandbox.d.ts.map +1 -0
- package/dist/commands/sandbox.js +88 -0
- package/dist/commands/sandbox.js.map +1 -0
- package/dist/commands/session-view.d.ts.map +1 -1
- package/dist/commands/session-view.js +34 -10
- package/dist/commands/session-view.js.map +1 -1
- package/dist/commands/types.d.ts +1 -3
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/types.js.map +1 -1
- package/dist/commands/utils.d.ts +3 -0
- package/dist/commands/utils.d.ts.map +1 -1
- package/dist/commands/utils.js +5 -0
- package/dist/commands/utils.js.map +1 -1
- package/dist/config.d.ts +7 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +64 -23
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +2 -44
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +7 -210
- package/dist/context.js.map +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +15 -14
- package/dist/events.js.map +1 -1
- package/dist/execution-resolver.d.ts +3 -2
- package/dist/execution-resolver.d.ts.map +1 -1
- package/dist/execution-resolver.js +40 -7
- package/dist/execution-resolver.js.map +1 -1
- package/dist/file-guards.d.ts +6 -0
- package/dist/file-guards.d.ts.map +1 -0
- package/dist/file-guards.js +48 -0
- package/dist/file-guards.js.map +1 -0
- package/dist/log.d.ts +1 -5
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +13 -38
- package/dist/log.js.map +1 -1
- package/dist/login/index.d.ts +14 -2
- package/dist/login/index.d.ts.map +1 -1
- package/dist/login/index.js +40 -13
- package/dist/login/index.js.map +1 -1
- package/dist/login/portal.d.ts +2 -1
- package/dist/login/portal.d.ts.map +1 -1
- package/dist/login/portal.js +12 -12
- package/dist/login/portal.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +33 -28
- package/dist/main.js.map +1 -1
- package/dist/provisioner.d.ts +12 -2
- package/dist/provisioner.d.ts.map +1 -1
- package/dist/provisioner.js +43 -14
- package/dist/provisioner.js.map +1 -1
- package/dist/runtime/conversation-orchestrator.d.ts +42 -0
- package/dist/runtime/conversation-orchestrator.d.ts.map +1 -0
- package/dist/runtime/conversation-orchestrator.js +150 -0
- package/dist/runtime/conversation-orchestrator.js.map +1 -0
- package/dist/runtime/session-runtime.d.ts +1 -1
- package/dist/runtime/session-runtime.d.ts.map +1 -1
- package/dist/runtime/session-runtime.js +49 -148
- package/dist/runtime/session-runtime.js.map +1 -1
- package/dist/sandbox/cloudflare.d.ts.map +1 -1
- package/dist/sandbox/cloudflare.js +2 -2
- package/dist/sandbox/cloudflare.js.map +1 -1
- package/dist/sandbox/container.d.ts.map +1 -1
- package/dist/sandbox/container.js +1 -1
- package/dist/sandbox/container.js.map +1 -1
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +4 -4
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sentry.d.ts +1 -1
- package/dist/sentry.d.ts.map +1 -1
- package/dist/sentry.js +2 -2
- package/dist/sentry.js.map +1 -1
- package/dist/session-store.d.ts +2 -1
- package/dist/session-store.d.ts.map +1 -1
- package/dist/session-store.js +19 -15
- package/dist/session-store.js.map +1 -1
- package/dist/session-view/portal.d.ts +6 -1
- package/dist/session-view/portal.d.ts.map +1 -1
- package/dist/session-view/portal.js +829 -71
- package/dist/session-view/portal.js.map +1 -1
- package/dist/session-view/service.d.ts.map +1 -1
- package/dist/session-view/service.js +5 -4
- package/dist/session-view/service.js.map +1 -1
- package/dist/session-view/store.d.ts +2 -1
- package/dist/session-view/store.d.ts.map +1 -1
- package/dist/session-view/store.js +2 -1
- package/dist/session-view/store.js.map +1 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +7 -13
- package/dist/store.js.map +1 -1
- package/dist/tool-diagnostics.d.ts +2 -0
- package/dist/tool-diagnostics.d.ts.map +1 -0
- package/dist/tool-diagnostics.js +7 -0
- package/dist/tool-diagnostics.js.map +1 -0
- package/dist/tools/bash.d.ts +1 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.d.ts +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/event.d.ts +1 -1
- package/dist/tools/event.d.ts.map +1 -1
- package/dist/tools/event.js.map +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/read.d.ts +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/write.d.ts +1 -1
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js.map +1 -1
- package/dist/vault-routing.d.ts +0 -3
- package/dist/vault-routing.d.ts.map +1 -1
- package/dist/vault-routing.js +0 -24
- package/dist/vault-routing.js.map +1 -1
- package/dist/vault.d.ts +21 -57
- package/dist/vault.d.ts.map +1 -1
- package/dist/vault.js +114 -246
- package/dist/vault.js.map +1 -1
- package/package.json +6 -4
- package/dist/bindings.d.ts +0 -45
- package/dist/bindings.d.ts.map +0 -1
- package/dist/bindings.js +0 -75
- package/dist/bindings.js.map +0 -1
|
@@ -15,6 +15,38 @@ function slackIsRateLimited(err) {
|
|
|
15
15
|
return data?.error === "rate_limited" || data?.response?.status === 429;
|
|
16
16
|
}
|
|
17
17
|
const slackRetry = (fn) => withRetry(fn, { isRateLimited: slackIsRateLimited });
|
|
18
|
+
function collectSlackText(value, parts) {
|
|
19
|
+
if (value === null || value === undefined)
|
|
20
|
+
return;
|
|
21
|
+
if (typeof value === "string") {
|
|
22
|
+
const trimmed = value.trim();
|
|
23
|
+
if (trimmed)
|
|
24
|
+
parts.push(trimmed);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (Array.isArray(value)) {
|
|
28
|
+
for (const item of value)
|
|
29
|
+
collectSlackText(item, parts);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (typeof value !== "object")
|
|
33
|
+
return;
|
|
34
|
+
const obj = value;
|
|
35
|
+
for (const key of ["text", "fallback", "title", "value"]) {
|
|
36
|
+
collectSlackText(obj[key], parts);
|
|
37
|
+
}
|
|
38
|
+
collectSlackText(obj.fields, parts);
|
|
39
|
+
collectSlackText(obj.elements, parts);
|
|
40
|
+
collectSlackText(obj.blocks, parts);
|
|
41
|
+
}
|
|
42
|
+
function buildSlackAppMessageText(event) {
|
|
43
|
+
const parts = [];
|
|
44
|
+
collectSlackText(event.text, parts);
|
|
45
|
+
collectSlackText(event.blocks, parts);
|
|
46
|
+
collectSlackText(event.attachments, parts);
|
|
47
|
+
const deduped = parts.filter((part, index) => parts.indexOf(part) === index);
|
|
48
|
+
return deduped.join("\n");
|
|
49
|
+
}
|
|
18
50
|
import { createSlackAdapters } from "./context.js";
|
|
19
51
|
import { hasMaterializedSlackBranchSession } from "./branch-manager.js";
|
|
20
52
|
import { resolveSlackSessionKey } from "./session.js";
|
|
@@ -24,6 +56,7 @@ import { resolveSlackSessionKey } from "./session.js";
|
|
|
24
56
|
export class SlackBot {
|
|
25
57
|
constructor(handler, config) {
|
|
26
58
|
this.botUserId = null;
|
|
59
|
+
this.botId = null;
|
|
27
60
|
this.ownMentionRegex = null;
|
|
28
61
|
this.startupTs = null; // Messages older than this are just logged, not processed
|
|
29
62
|
this.users = new Map();
|
|
@@ -33,7 +66,12 @@ export class SlackBot {
|
|
|
33
66
|
this.handler = handler;
|
|
34
67
|
this.workingDir = config.workingDir;
|
|
35
68
|
this.store = config.store;
|
|
36
|
-
this.socketClient = new SocketModeClient({
|
|
69
|
+
this.socketClient = new SocketModeClient({
|
|
70
|
+
appToken: config.appToken,
|
|
71
|
+
// Default 5s is too tight: brief event-loop stalls (e.g. backfill, sync fs)
|
|
72
|
+
// cause false pong timeouts; 4 in a row makes Slack drop the socket.
|
|
73
|
+
clientPingTimeout: 12_000,
|
|
74
|
+
});
|
|
37
75
|
this.webClient = new WebClient(config.botToken);
|
|
38
76
|
}
|
|
39
77
|
setEventsWatcher(watcher) {
|
|
@@ -45,6 +83,7 @@ export class SlackBot {
|
|
|
45
83
|
async start() {
|
|
46
84
|
const auth = await this.webClient.auth.test();
|
|
47
85
|
this.botUserId = auth.user_id;
|
|
86
|
+
this.botId = typeof auth.bot_id === "string" ? auth.bot_id : null;
|
|
48
87
|
await Promise.all([this.fetchUsers(), this.fetchChannels()]);
|
|
49
88
|
log.logInfo(`Loaded ${this.channels.size} channels, ${this.users.size} users`);
|
|
50
89
|
await this.backfillAllChannels();
|
|
@@ -52,7 +91,7 @@ export class SlackBot {
|
|
|
52
91
|
await this.socketClient.start();
|
|
53
92
|
// Record startup time - messages older than this are just logged, not processed
|
|
54
93
|
this.startupTs = (Date.now() / 1000).toFixed(6);
|
|
55
|
-
log.logConnected();
|
|
94
|
+
log.logConnected("Slack");
|
|
56
95
|
}
|
|
57
96
|
getUser(userId) {
|
|
58
97
|
return this.users.get(userId);
|
|
@@ -86,9 +125,37 @@ export class SlackBot {
|
|
|
86
125
|
await this.webClient.chat.postEphemeral({ channel, user, text });
|
|
87
126
|
});
|
|
88
127
|
}
|
|
128
|
+
async postEphemeralBlocks(channel, user, text, blocks) {
|
|
129
|
+
return slackRetry(async () => {
|
|
130
|
+
await this.webClient.chat.postEphemeral({ channel, user, text, blocks: blocks });
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
async postMessageBlocks(channel, text, blocks) {
|
|
134
|
+
return slackRetry(async () => {
|
|
135
|
+
const result = await this.webClient.chat.postMessage({
|
|
136
|
+
channel,
|
|
137
|
+
text,
|
|
138
|
+
blocks: blocks,
|
|
139
|
+
});
|
|
140
|
+
return result.ts;
|
|
141
|
+
});
|
|
142
|
+
}
|
|
89
143
|
async postPrivate(conversationId, userId, text) {
|
|
90
144
|
await this.postEphemeral(conversationId, userId, text);
|
|
91
145
|
}
|
|
146
|
+
async postPrivateDiagnostic(conversationId, userId, text, options) {
|
|
147
|
+
if (options?.style !== "muted") {
|
|
148
|
+
await this.postPrivate(conversationId, userId, options?.style === "error" ? `_${text}_` : text);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const CONTEXT_TEXT_LIMIT = 3000;
|
|
152
|
+
const blockText = text.length > CONTEXT_TEXT_LIMIT
|
|
153
|
+
? text.substring(0, CONTEXT_TEXT_LIMIT - 20) + "\n_(truncated)_"
|
|
154
|
+
: text;
|
|
155
|
+
await this.postEphemeralBlocks(conversationId, userId, text, [
|
|
156
|
+
{ type: "context", elements: [{ type: "mrkdwn", text: blockText }] },
|
|
157
|
+
]);
|
|
158
|
+
}
|
|
92
159
|
async openDirectMessage(userId) {
|
|
93
160
|
return slackRetry(async () => {
|
|
94
161
|
const result = await this.webClient.conversations.open({ users: userId });
|
|
@@ -419,10 +486,29 @@ export class SlackBot {
|
|
|
419
486
|
const messageTs = await this.postMessage(conversationId, responseText);
|
|
420
487
|
this.logBotResponse(conversationId, responseText, messageTs);
|
|
421
488
|
};
|
|
489
|
+
const respondMuted = async (responseText) => {
|
|
490
|
+
const CONTEXT_TEXT_LIMIT = 3000;
|
|
491
|
+
const blockText = responseText.length > CONTEXT_TEXT_LIMIT
|
|
492
|
+
? responseText.substring(0, CONTEXT_TEXT_LIMIT - 20) + "\n_(truncated)_"
|
|
493
|
+
: responseText;
|
|
494
|
+
const blocks = [{ type: "context", elements: [{ type: "mrkdwn", text: blockText }] }];
|
|
495
|
+
if (options.ephemeralChannelId) {
|
|
496
|
+
await this.postEphemeralBlocks(options.ephemeralChannelId, userId, responseText, blocks);
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
const messageTs = await this.postMessageBlocks(conversationId, responseText, blocks);
|
|
500
|
+
this.logBotResponse(conversationId, responseText, messageTs);
|
|
501
|
+
};
|
|
422
502
|
const responseCtx = {
|
|
423
503
|
respond,
|
|
424
504
|
replaceResponse: respond,
|
|
425
|
-
respondDiagnostic:
|
|
505
|
+
respondDiagnostic: async (responseText, responseOptions) => {
|
|
506
|
+
if (responseOptions?.style === "muted") {
|
|
507
|
+
await respondMuted(responseText);
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
await respond(responseOptions?.style === "error" ? `_${responseText}_` : responseText);
|
|
511
|
+
},
|
|
426
512
|
respondToolResult: async (result) => {
|
|
427
513
|
const duration = (result.durationMs / 1000).toFixed(1);
|
|
428
514
|
await respond(`${result.isError ? "Error" : "Done"} ${result.toolName} (${duration}s)\n${result.result}`);
|
|
@@ -512,7 +598,7 @@ export class SlackBot {
|
|
|
512
598
|
isBot: false,
|
|
513
599
|
});
|
|
514
600
|
const commandBot = this.createSlashCommandBot(conversationId);
|
|
515
|
-
await this.handler.
|
|
601
|
+
await this.handler.handleNewCommand(conversationId, conversationId, commandBot);
|
|
516
602
|
}
|
|
517
603
|
async routeSlashModelCommand(payload) {
|
|
518
604
|
const conversationId = payload.channel_id;
|
|
@@ -545,6 +631,9 @@ export class SlackBot {
|
|
|
545
631
|
const adapters = this.createCommandAdapters(conversationId, payload.user_id, userName, commandText, eventTs, isDirectMessage ? {} : { ephemeralChannelId: conversationId });
|
|
546
632
|
await this.handler.handleEvent(event, this, adapters, false);
|
|
547
633
|
}
|
|
634
|
+
async routeSlashSandboxCommand(payload) {
|
|
635
|
+
await this.routeSlashModelCommand(payload);
|
|
636
|
+
}
|
|
548
637
|
async routeSlashSessionCommand(payload) {
|
|
549
638
|
const conversationId = payload.channel_id;
|
|
550
639
|
const isDirectMessage = conversationId.startsWith("D");
|
|
@@ -576,6 +665,15 @@ export class SlackBot {
|
|
|
576
665
|
await this.handler.handleEvent(event, this, adapters, false);
|
|
577
666
|
}
|
|
578
667
|
setupEventHandlers() {
|
|
668
|
+
this.socketClient.on("disconnect", (err) => {
|
|
669
|
+
log.logWarning("Slack socket disconnect", err ? String(err) : "");
|
|
670
|
+
});
|
|
671
|
+
this.socketClient.on("error", (err) => {
|
|
672
|
+
log.logWarning("Slack socket error", err ? String(err) : "");
|
|
673
|
+
});
|
|
674
|
+
this.socketClient.on("unable_to_socket_mode_start", (err) => {
|
|
675
|
+
log.logWarning("Slack socket unable_to_start", err ? String(err) : "");
|
|
676
|
+
});
|
|
579
677
|
// Channel @mentions
|
|
580
678
|
this.socketClient.on("app_mention", ({ event, ack }) => {
|
|
581
679
|
const e = event;
|
|
@@ -634,8 +732,30 @@ export class SlackBot {
|
|
|
634
732
|
// All messages (for logging) + DMs (for triggering)
|
|
635
733
|
this.socketClient.on("message", ({ event, ack }) => {
|
|
636
734
|
const e = event;
|
|
637
|
-
|
|
638
|
-
|
|
735
|
+
const hasFiles = !!e.files && e.files.length > 0;
|
|
736
|
+
const hasSlackContent = !!e.text || hasFiles || !!e.blocks?.length || !!e.attachments?.length;
|
|
737
|
+
const isOwnBotMessage = (!!e.user && e.user === this.botUserId) || (!!this.botId && e.bot_id === this.botId);
|
|
738
|
+
if (isOwnBotMessage) {
|
|
739
|
+
ack();
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
const isExternalBotMessage = !!e.bot_id || e.subtype === "bot_message";
|
|
743
|
+
if (isExternalBotMessage) {
|
|
744
|
+
if (e.subtype !== undefined && e.subtype !== "bot_message" && e.subtype !== "file_share") {
|
|
745
|
+
ack();
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
if (!hasSlackContent) {
|
|
749
|
+
ack();
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
void this.logExternalBotMessage(e).catch((err) => {
|
|
753
|
+
log.logWarning("Failed to log Slack bot message", String(err));
|
|
754
|
+
});
|
|
755
|
+
ack();
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
if (!e.user) {
|
|
639
759
|
ack();
|
|
640
760
|
return;
|
|
641
761
|
}
|
|
@@ -643,7 +763,7 @@ export class SlackBot {
|
|
|
643
763
|
ack();
|
|
644
764
|
return;
|
|
645
765
|
}
|
|
646
|
-
if (!
|
|
766
|
+
if (!hasSlackContent) {
|
|
647
767
|
ack();
|
|
648
768
|
return;
|
|
649
769
|
}
|
|
@@ -762,7 +882,15 @@ export class SlackBot {
|
|
|
762
882
|
user_id: payload.user_id,
|
|
763
883
|
user_name: payload.user_name,
|
|
764
884
|
})
|
|
765
|
-
:
|
|
885
|
+
: payload.command === "/pi-sandbox"
|
|
886
|
+
? this.routeSlashSandboxCommand({
|
|
887
|
+
command: payload.command,
|
|
888
|
+
text: payload.text,
|
|
889
|
+
channel_id: payload.channel_id,
|
|
890
|
+
user_id: payload.user_id,
|
|
891
|
+
user_name: payload.user_name,
|
|
892
|
+
})
|
|
893
|
+
: null;
|
|
766
894
|
if (!handlerPromise) {
|
|
767
895
|
return;
|
|
768
896
|
}
|
|
@@ -835,6 +963,27 @@ export class SlackBot {
|
|
|
835
963
|
});
|
|
836
964
|
return attachments;
|
|
837
965
|
}
|
|
966
|
+
async logExternalBotMessage(event) {
|
|
967
|
+
const attachments = event.files
|
|
968
|
+
? await this.store.processAttachments(event.channel, event.files, event.ts)
|
|
969
|
+
: [];
|
|
970
|
+
const botName = event.username ?? event.bot_profile?.name ?? event.bot_profile?.real_name ?? event.bot_id;
|
|
971
|
+
this.logToFile(event.channel, {
|
|
972
|
+
date: new Date(parseFloat(event.ts) * 1000).toISOString(),
|
|
973
|
+
ts: event.ts,
|
|
974
|
+
threadTs: event.thread_ts,
|
|
975
|
+
user: event.bot_id ? `bot:${event.bot_id}` : "external-bot",
|
|
976
|
+
userName: botName,
|
|
977
|
+
displayName: botName,
|
|
978
|
+
text: buildSlackAppMessageText(event),
|
|
979
|
+
attachments,
|
|
980
|
+
isBot: true,
|
|
981
|
+
botId: event.bot_id,
|
|
982
|
+
appId: event.app_id ?? event.bot_profile?.app_id,
|
|
983
|
+
subtype: event.subtype,
|
|
984
|
+
});
|
|
985
|
+
return attachments;
|
|
986
|
+
}
|
|
838
987
|
// ==========================================================================
|
|
839
988
|
// Private - Backfill
|
|
840
989
|
// ==========================================================================
|
|
@@ -883,14 +1032,26 @@ export class SlackBot {
|
|
|
883
1032
|
cursor = result.response_metadata?.next_cursor;
|
|
884
1033
|
pageCount++;
|
|
885
1034
|
} while (cursor && pageCount < maxPages);
|
|
886
|
-
// Filter: include mama's messages,
|
|
1035
|
+
// Filter: include mama's messages, external app/bot messages, and user messages.
|
|
887
1036
|
const relevantMessages = allMessages.filter((msg) => {
|
|
888
1037
|
if (!msg.ts || existingTs.has(msg.ts))
|
|
889
1038
|
return false; // Skip duplicates
|
|
890
1039
|
if (msg.user === this.botUserId)
|
|
891
1040
|
return true;
|
|
892
|
-
|
|
893
|
-
|
|
1041
|
+
const isExternalBotMessage = !!msg.bot_id || msg.subtype === "bot_message";
|
|
1042
|
+
if (isExternalBotMessage) {
|
|
1043
|
+
if (this.botId && msg.bot_id === this.botId)
|
|
1044
|
+
return false;
|
|
1045
|
+
if (msg.subtype !== undefined &&
|
|
1046
|
+
msg.subtype !== "bot_message" &&
|
|
1047
|
+
msg.subtype !== "file_share") {
|
|
1048
|
+
return false;
|
|
1049
|
+
}
|
|
1050
|
+
return (!!msg.text ||
|
|
1051
|
+
!!(msg.files && msg.files.length > 0) ||
|
|
1052
|
+
!!msg.blocks?.length ||
|
|
1053
|
+
!!msg.attachments?.length);
|
|
1054
|
+
}
|
|
894
1055
|
if (msg.subtype !== undefined && msg.subtype !== "file_share")
|
|
895
1056
|
return false;
|
|
896
1057
|
if (!msg.user)
|
|
@@ -904,6 +1065,11 @@ export class SlackBot {
|
|
|
904
1065
|
// Log each message to log.jsonl
|
|
905
1066
|
for (const msg of relevantMessages) {
|
|
906
1067
|
const isMamaMessage = msg.user === this.botUserId;
|
|
1068
|
+
const isExternalBotMessage = !isMamaMessage && (!!msg.bot_id || msg.subtype === "bot_message");
|
|
1069
|
+
if (isExternalBotMessage) {
|
|
1070
|
+
await this.logExternalBotMessage({ ...msg, channel: channelId, ts: msg.ts });
|
|
1071
|
+
continue;
|
|
1072
|
+
}
|
|
907
1073
|
const user = this.users.get(msg.user);
|
|
908
1074
|
const text = this.stripOwnMention(msg.text);
|
|
909
1075
|
const attachments = msg.files
|