@credal/actions 0.2.110 → 0.2.112

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.
@@ -4,13 +4,14 @@ export interface SlackSearchMessage {
4
4
  channelId: string;
5
5
  ts: string;
6
6
  text?: string;
7
- userId?: string;
7
+ userEmail?: string;
8
8
  permalink?: string;
9
9
  /** If thread: full thread (root first). If not thread: small context window around the hit. */
10
10
  context?: Array<{
11
11
  ts: string;
12
12
  text?: string;
13
- userId?: string;
13
+ userEmail?: string;
14
+ userName?: string;
14
15
  }>;
15
16
  }
16
17
  declare const searchSlack: slackUserSearchSlackFunction;
@@ -9,6 +9,37 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { WebClient } from "@slack/web-api";
11
11
  import { MISSING_AUTH_TOKEN } from "../../util/missingAuthConstants.js";
12
+ import pLimit from "p-limit";
13
+ const HIT_ENRICH_POOL = 10;
14
+ const limitHit = pLimit(HIT_ENRICH_POOL);
15
+ class SlackUserCache {
16
+ constructor(client) {
17
+ this.client = client;
18
+ this.cache = new Map();
19
+ this.client = client;
20
+ }
21
+ get(id) {
22
+ return __awaiter(this, void 0, void 0, function* () {
23
+ var _a, _b, _c, _d, _e, _f, _g, _h;
24
+ const result = this.cache.get(id);
25
+ if (result)
26
+ return result;
27
+ const res = yield this.client.users.info({ user: id });
28
+ const u = {
29
+ name: (_e = (_c = (_b = (_a = res.user) === null || _a === void 0 ? void 0 : _a.profile) === null || _b === void 0 ? void 0 : _b.display_name) !== null && _c !== void 0 ? _c : (_d = res.user) === null || _d === void 0 ? void 0 : _d.real_name) !== null && _e !== void 0 ? _e : "",
30
+ email: (_h = (_g = (_f = res.user) === null || _f === void 0 ? void 0 : _f.profile) === null || _g === void 0 ? void 0 : _g.email) !== null && _h !== void 0 ? _h : "",
31
+ };
32
+ if (res.user && id && res.user.name) {
33
+ this.cache.set(id, u);
34
+ return u;
35
+ }
36
+ return undefined;
37
+ });
38
+ }
39
+ set(id, { email, name }) {
40
+ this.cache.set(id, { email, name });
41
+ }
42
+ }
12
43
  /* ===================== Helpers ===================== */
13
44
  function normalizeChannelOperand(ch) {
14
45
  const s = ch.trim();
@@ -30,19 +61,27 @@ function timeFilter(range) {
30
61
  return "";
31
62
  }
32
63
  }
33
- function lookupUserIdsByEmail(client, emails) {
64
+ function lookupUserIdsByEmail(client, emails, slackUserCache) {
34
65
  return __awaiter(this, void 0, void 0, function* () {
35
- var _a;
36
66
  const ids = [];
37
- for (const raw of emails) {
67
+ const tasks = emails.map((raw) => __awaiter(this, void 0, void 0, function* () {
68
+ var _a;
38
69
  const email = raw.trim();
39
70
  if (!email)
40
- continue;
71
+ return null;
41
72
  const res = yield client.users.lookupByEmail({ email });
42
73
  const id = (_a = res.user) === null || _a === void 0 ? void 0 : _a.id;
74
+ if (res.user && id && res.user.name) {
75
+ slackUserCache.set(id, { email, name: res.user.name });
76
+ }
43
77
  if (id)
44
- ids.push(id);
45
- }
78
+ return id;
79
+ return null;
80
+ }));
81
+ const settled = yield Promise.allSettled(tasks);
82
+ for (const r of settled)
83
+ if (r.status === "fulfilled" && r.value)
84
+ ids.push(r.value);
46
85
  return ids;
47
86
  });
48
87
  }
@@ -119,22 +158,27 @@ function fetchContextWindow(client, channel, ts) {
119
158
  }
120
159
  /* ===================== Main Export ===================== */
121
160
  const searchSlack = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
122
- var _b, _c, _d, _e, _f, _g;
161
+ var _b, _c;
123
162
  if (!authParams.authToken) {
124
163
  throw new Error(MISSING_AUTH_TOKEN);
125
164
  }
126
165
  const client = new WebClient(authParams.authToken);
166
+ const slackUserCache = new SlackUserCache(client);
127
167
  const { emails, channel, topic, timeRange, limit } = params;
128
168
  const parts = [];
129
169
  if (emails === null || emails === void 0 ? void 0 : emails.length) {
130
- const userIds = yield lookupUserIdsByEmail(client, emails);
131
- if (userIds.length === 0)
170
+ const userIds = yield lookupUserIdsByEmail(client, emails, slackUserCache);
171
+ const { user_id: myUserId } = yield client.auth.test();
172
+ if (!myUserId)
173
+ throw new Error("Failed to get my user ID.");
174
+ const userIdsWithoutMe = userIds.filter(id => id !== myUserId);
175
+ if (userIdsWithoutMe.length === 0)
132
176
  throw new Error("No users resolved from emails.");
133
- if (userIds.length == 1) {
134
- parts.push(`in:<@${userIds[0]}>`);
177
+ if (userIdsWithoutMe.length == 1) {
178
+ parts.push(`in:<@${userIdsWithoutMe[0]}>`);
135
179
  }
136
180
  else {
137
- const convoName = yield getMPIMName(client, userIds);
181
+ const convoName = yield getMPIMName(client, userIdsWithoutMe);
138
182
  parts.push(`in:${convoName}`);
139
183
  }
140
184
  }
@@ -152,67 +196,103 @@ const searchSlack = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params,
152
196
  const count = Math.max(1, Math.min(100, limit));
153
197
  const searchRes = yield client.search.messages({ query, count, highlight: true });
154
198
  const matches = (_c = (_b = searchRes.messages) === null || _b === void 0 ? void 0 : _b.matches) !== null && _c !== void 0 ? _c : [];
155
- const hits = matches.slice(0, limit).map(m => {
156
- var _a, _b;
157
- return ({
199
+ const hitsPromises = matches.slice(0, limit).map((m) => __awaiter(void 0, void 0, void 0, function* () {
200
+ var _a, _b, _c, _d;
201
+ const user = m.user ? yield slackUserCache.get(m.user) : undefined;
202
+ return {
158
203
  channelId: ((_a = m.channel) === null || _a === void 0 ? void 0 : _a.id) || ((_b = m.channel) === null || _b === void 0 ? void 0 : _b.name) || "",
159
204
  ts: m.ts,
160
205
  text: m.text,
161
- userId: m.user,
162
- });
163
- });
164
- const results = [];
165
- for (const h of hits) {
206
+ userEmail: (_c = user === null || user === void 0 ? void 0 : user.email) !== null && _c !== void 0 ? _c : undefined,
207
+ userName: (_d = user === null || user === void 0 ? void 0 : user.name) !== null && _d !== void 0 ? _d : undefined,
208
+ };
209
+ }));
210
+ const hits = yield Promise.all(hitsPromises);
211
+ const tasks = hits.map(h => limitHit(() => __awaiter(void 0, void 0, void 0, function* () {
212
+ var _a, _b, _c, _d, _e, _f;
166
213
  if (!h.ts)
167
- continue;
214
+ return null;
168
215
  try {
169
216
  const anchor = yield fetchOneMessage(client, h.channelId, h.ts);
170
217
  const rootTs = (anchor === null || anchor === void 0 ? void 0 : anchor.thread_ts) || h.ts;
171
218
  if (anchor === null || anchor === void 0 ? void 0 : anchor.thread_ts) {
172
- const thread = yield fetchThread(client, h.channelId, rootTs);
173
- const normalizedThreads = [];
174
- for (const t of thread) {
175
- if (!t.ts)
176
- continue;
177
- normalizedThreads.push({ ts: t.ts, text: t.text, userId: t.user });
178
- }
179
- results.push({
219
+ // thread: fetch thread + permalink concurrently
220
+ const [thread, permalink] = yield Promise.all([
221
+ fetchThread(client, h.channelId, rootTs),
222
+ getPermalink(client, h.channelId, rootTs),
223
+ ]);
224
+ const contextPromises = thread
225
+ .filter(t => t.ts)
226
+ .map((t) => __awaiter(void 0, void 0, void 0, function* () {
227
+ var _a, _b;
228
+ const user = t.user ? yield slackUserCache.get(t.user) : undefined;
229
+ return {
230
+ ts: t.ts,
231
+ text: t.text,
232
+ userEmail: (_a = user === null || user === void 0 ? void 0 : user.email) !== null && _a !== void 0 ? _a : undefined,
233
+ userName: (_b = user === null || user === void 0 ? void 0 : user.name) !== null && _b !== void 0 ? _b : undefined,
234
+ };
235
+ }));
236
+ const context = yield Promise.all(contextPromises);
237
+ const user = anchor.user ? yield slackUserCache.get(anchor.user) : undefined;
238
+ return {
180
239
  channelId: h.channelId,
181
240
  ts: rootTs,
182
- text: (_d = anchor.text) !== null && _d !== void 0 ? _d : h.text,
183
- userId: (_e = anchor.user) !== null && _e !== void 0 ? _e : h.userId,
184
- context: normalizedThreads,
185
- permalink: yield getPermalink(client, h.channelId, rootTs),
186
- });
241
+ text: (_a = anchor.text) !== null && _a !== void 0 ? _a : h.text,
242
+ userEmail: (_b = user === null || user === void 0 ? void 0 : user.email) !== null && _b !== void 0 ? _b : h.userEmail,
243
+ userName: (_c = user === null || user === void 0 ? void 0 : user.name) !== null && _c !== void 0 ? _c : h.userName,
244
+ context,
245
+ permalink,
246
+ };
187
247
  }
188
248
  else {
189
- const ctx = yield fetchContextWindow(client, h.channelId, h.ts);
190
- const normalizedThreads = [];
191
- for (const t of ctx) {
192
- if (!t.ts)
193
- continue;
194
- normalizedThreads.push({ ts: t.ts, text: t.text, userId: t.user });
195
- }
196
- results.push({
249
+ // not a thread: fetch context window + permalink concurrently
250
+ const [ctx, permalink] = yield Promise.all([
251
+ fetchContextWindow(client, h.channelId, h.ts),
252
+ getPermalink(client, h.channelId, h.ts),
253
+ ]);
254
+ const contextPromises = ctx
255
+ .filter(t => t.ts)
256
+ .map((t) => __awaiter(void 0, void 0, void 0, function* () {
257
+ var _a, _b;
258
+ const user = t.user ? yield slackUserCache.get(t.user) : undefined;
259
+ return {
260
+ ts: t.ts,
261
+ text: t.text,
262
+ userEmail: (_a = user === null || user === void 0 ? void 0 : user.email) !== null && _a !== void 0 ? _a : undefined,
263
+ userName: (_b = user === null || user === void 0 ? void 0 : user.name) !== null && _b !== void 0 ? _b : undefined,
264
+ };
265
+ }));
266
+ const context = yield Promise.all(contextPromises);
267
+ const user = (anchor === null || anchor === void 0 ? void 0 : anchor.user) ? yield slackUserCache.get(anchor.user) : undefined;
268
+ return {
197
269
  channelId: h.channelId,
198
270
  ts: h.ts,
199
- text: (_f = anchor === null || anchor === void 0 ? void 0 : anchor.text) !== null && _f !== void 0 ? _f : h.text,
200
- userId: (_g = anchor === null || anchor === void 0 ? void 0 : anchor.user) !== null && _g !== void 0 ? _g : h.userId,
201
- context: normalizedThreads,
202
- permalink: yield getPermalink(client, h.channelId, h.ts),
203
- });
271
+ text: (_d = anchor === null || anchor === void 0 ? void 0 : anchor.text) !== null && _d !== void 0 ? _d : h.text,
272
+ userEmail: (_e = user === null || user === void 0 ? void 0 : user.email) !== null && _e !== void 0 ? _e : h.userEmail,
273
+ userName: (_f = user === null || user === void 0 ? void 0 : user.name) !== null && _f !== void 0 ? _f : h.userName,
274
+ context,
275
+ permalink,
276
+ };
204
277
  }
205
278
  }
206
- catch (_h) {
207
- results.push({
279
+ catch (_g) {
280
+ // fallback minimal object; still in parallel
281
+ return {
208
282
  channelId: h.channelId,
209
283
  ts: h.ts,
210
284
  text: h.text,
211
- userId: h.userId,
285
+ userEmail: h.userEmail,
286
+ userName: h.userName,
212
287
  permalink: yield getPermalink(client, h.channelId, h.ts),
213
- });
288
+ };
214
289
  }
215
- }
290
+ })));
291
+ const settled = yield Promise.allSettled(tasks);
292
+ const results = [];
293
+ for (const r of settled)
294
+ if (r.status === "fulfilled" && r.value)
295
+ results.push(r.value);
216
296
  results.sort((a, b) => Number(b.ts) - Number(a.ts));
217
297
  return { query, results };
218
298
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@credal/actions",
3
- "version": "0.2.110",
3
+ "version": "0.2.112",
4
4
  "type": "module",
5
5
  "description": "AI Actions by Credal AI",
6
6
  "sideEffects": false,
@@ -66,6 +66,7 @@
66
66
  "mammoth": "^1.4.27",
67
67
  "mongodb": "^6.13.1",
68
68
  "node-forge": "^1.3.1",
69
+ "p-limit": "^7.1.1",
69
70
  "pdf2json": "^3.1.6",
70
71
  "resend": "^4.7.0",
71
72
  "snowflake-sdk": "^2.0.2",