@anuma/sdk 1.0.0-next.20260710194151 → 1.1.0
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 +14 -0
- package/dist/index.cjs +0 -1
- package/dist/index.mjs +0 -1
- package/dist/server/index.cjs +0 -1
- package/dist/server/index.mjs +0 -1
- package/dist/tools/index.cjs +58 -412
- package/dist/tools/index.d.mts +3 -14
- package/dist/tools/index.d.ts +3 -14
- package/dist/tools/index.mjs +58 -412
- package/package.json +1 -1
package/dist/tools/index.mjs
CHANGED
|
@@ -3246,7 +3246,6 @@ function createDropboxTools(getToken, requestAccess) {
|
|
|
3246
3246
|
|
|
3247
3247
|
// src/tools/slack.ts
|
|
3248
3248
|
var SLACK_PROVIDER = "slack";
|
|
3249
|
-
var SLACK_PENDING_APPROVAL_NOTE = "This Slack request couldn't be completed because Slack rate-limited the app. The Slack app is still pending Slack Marketplace approval, so these reads aren't available yet. Tell the user this is a temporary limitation until the app is approved; do not attempt a workaround.";
|
|
3250
3249
|
var AUTH_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
3251
3250
|
"not_authed",
|
|
3252
3251
|
"invalid_auth",
|
|
@@ -3270,10 +3269,8 @@ function maybeConnectorError4(status, body) {
|
|
|
3270
3269
|
}
|
|
3271
3270
|
return null;
|
|
3272
3271
|
}
|
|
3273
|
-
function
|
|
3274
|
-
|
|
3275
|
-
}
|
|
3276
|
-
function interpretSlackResult(path, status, json) {
|
|
3272
|
+
async function callSlack(callProxy, path, query, requestBody) {
|
|
3273
|
+
const { status, json } = await callProxy(path, query, requestBody);
|
|
3277
3274
|
const body = json ?? null;
|
|
3278
3275
|
if (status < 200 || status >= 300) {
|
|
3279
3276
|
const connectorError = maybeConnectorError4(status, body);
|
|
@@ -3287,10 +3284,6 @@ function interpretSlackResult(path, status, json) {
|
|
|
3287
3284
|
}
|
|
3288
3285
|
return body;
|
|
3289
3286
|
}
|
|
3290
|
-
async function callSlack(callProxy, path, query, requestBody) {
|
|
3291
|
-
const { status, json } = await callProxy(path, query, requestBody);
|
|
3292
|
-
return interpretSlackResult(path, status, json);
|
|
3293
|
-
}
|
|
3294
3287
|
function readString(raw) {
|
|
3295
3288
|
return typeof raw === "string" ? raw : "";
|
|
3296
3289
|
}
|
|
@@ -3299,70 +3292,6 @@ function clampLimit(raw, fallback, min, max) {
|
|
|
3299
3292
|
const safe = typeof num === "number" && Number.isFinite(num) ? num : fallback;
|
|
3300
3293
|
return Math.min(max, Math.max(min, safe));
|
|
3301
3294
|
}
|
|
3302
|
-
function makeGetAuthUserId(callProxy) {
|
|
3303
|
-
let cached;
|
|
3304
|
-
return async () => {
|
|
3305
|
-
if (cached === void 0) {
|
|
3306
|
-
const auth = await callSlack(callProxy, "/auth.test");
|
|
3307
|
-
cached = typeof auth === "string" ? null : auth.user_id ?? null;
|
|
3308
|
-
}
|
|
3309
|
-
return cached;
|
|
3310
|
-
};
|
|
3311
|
-
}
|
|
3312
|
-
function displayNameForUser(user) {
|
|
3313
|
-
return user.profile?.display_name || user.real_name || user.name || user.id;
|
|
3314
|
-
}
|
|
3315
|
-
function authorName(m, directory) {
|
|
3316
|
-
const known = m.user ? directory.byId.get(m.user) : void 0;
|
|
3317
|
-
return known && displayNameForUser(known) || m.username || m.user || "";
|
|
3318
|
-
}
|
|
3319
|
-
var USER_MENTION_RE = /<@([UW][A-Z0-9]+)(?:\|([^>]+))?>/g;
|
|
3320
|
-
var CHANNEL_MENTION_RE = /<#(C[A-Z0-9]+)(?:\|([^>]+))?>/g;
|
|
3321
|
-
function humanizeSlackText(text, directory) {
|
|
3322
|
-
return text.replace(USER_MENTION_RE, (_match, id, handle) => {
|
|
3323
|
-
const known = directory.byId.get(id);
|
|
3324
|
-
return `@${known && displayNameForUser(known) || handle || id}`;
|
|
3325
|
-
}).replace(
|
|
3326
|
-
CHANNEL_MENTION_RE,
|
|
3327
|
-
(match, _id, name) => name ? `#${name}` : match
|
|
3328
|
-
);
|
|
3329
|
-
}
|
|
3330
|
-
var MAX_USERS_PAGES = 10;
|
|
3331
|
-
async function listAllUsers(callProxy) {
|
|
3332
|
-
const all = [];
|
|
3333
|
-
let cursor = "";
|
|
3334
|
-
for (let page = 0; page < MAX_USERS_PAGES; page++) {
|
|
3335
|
-
const query = { limit: 1e3 };
|
|
3336
|
-
if (cursor) query.cursor = cursor;
|
|
3337
|
-
const res = await callSlack(callProxy, "/users.list", query);
|
|
3338
|
-
if (typeof res === "string") {
|
|
3339
|
-
if (page === 0) return res;
|
|
3340
|
-
break;
|
|
3341
|
-
}
|
|
3342
|
-
all.push(...res.members ?? []);
|
|
3343
|
-
const next = res.response_metadata?.next_cursor;
|
|
3344
|
-
if (!next) break;
|
|
3345
|
-
cursor = next;
|
|
3346
|
-
}
|
|
3347
|
-
return all;
|
|
3348
|
-
}
|
|
3349
|
-
function makeGetUsersDirectory(callProxy) {
|
|
3350
|
-
let cached;
|
|
3351
|
-
return async () => {
|
|
3352
|
-
if (cached === void 0) {
|
|
3353
|
-
const res = await listAllUsers(callProxy);
|
|
3354
|
-
const members = (typeof res === "string" ? [] : res).filter((u) => !u.deleted);
|
|
3355
|
-
const byId = /* @__PURE__ */ new Map();
|
|
3356
|
-
const byHandle = /* @__PURE__ */ new Map();
|
|
3357
|
-
for (const user of members) {
|
|
3358
|
-
byId.set(user.id, user);
|
|
3359
|
-
if (user.name) byHandle.set(user.name.toLowerCase(), user);
|
|
3360
|
-
}
|
|
3361
|
-
cached = { members, byId, byHandle };
|
|
3362
|
-
}
|
|
3363
|
-
return cached;
|
|
3364
|
-
};
|
|
3365
|
-
}
|
|
3366
3295
|
async function getSlackMe(callProxy) {
|
|
3367
3296
|
const auth = await callSlack(callProxy, "/auth.test");
|
|
3368
3297
|
if (typeof auth === "string") return auth;
|
|
@@ -3385,10 +3314,14 @@ async function getSlackMe(callProxy) {
|
|
|
3385
3314
|
};
|
|
3386
3315
|
}
|
|
3387
3316
|
async function listSlackChannels(callProxy, args) {
|
|
3388
|
-
const limit = clampLimit(args.limit,
|
|
3389
|
-
const res = await
|
|
3317
|
+
const limit = clampLimit(args.limit, 100, 1, 1e3);
|
|
3318
|
+
const res = await callSlack(callProxy, "/conversations.list", {
|
|
3319
|
+
limit,
|
|
3320
|
+
exclude_archived: "true",
|
|
3321
|
+
types: "public_channel,private_channel"
|
|
3322
|
+
});
|
|
3390
3323
|
if (typeof res === "string") return res;
|
|
3391
|
-
return res.
|
|
3324
|
+
return (res.channels ?? []).map((c) => ({
|
|
3392
3325
|
id: c.id,
|
|
3393
3326
|
name: c.name,
|
|
3394
3327
|
is_private: c.is_private,
|
|
@@ -3397,150 +3330,8 @@ async function listSlackChannels(callProxy, args) {
|
|
|
3397
3330
|
purpose: c.purpose?.value
|
|
3398
3331
|
}));
|
|
3399
3332
|
}
|
|
3400
|
-
var MAX_DM_PROBES = 50;
|
|
3401
|
-
async function openSlackDm(callProxy, userId) {
|
|
3402
|
-
const res = await callSlack(
|
|
3403
|
-
callProxy,
|
|
3404
|
-
"/conversations.open",
|
|
3405
|
-
void 0,
|
|
3406
|
-
{ users: userId }
|
|
3407
|
-
);
|
|
3408
|
-
if (typeof res === "string") return null;
|
|
3409
|
-
return res.channel?.id ?? null;
|
|
3410
|
-
}
|
|
3411
|
-
async function dmHasMessages(callProxy, channelId) {
|
|
3412
|
-
const { status, json } = await callProxy("/conversations.history", {
|
|
3413
|
-
channel: channelId,
|
|
3414
|
-
limit: 1
|
|
3415
|
-
});
|
|
3416
|
-
const body = json ?? null;
|
|
3417
|
-
if (isRateLimited(status, body)) return true;
|
|
3418
|
-
const res = interpretSlackResult(
|
|
3419
|
-
"/conversations.history",
|
|
3420
|
-
status,
|
|
3421
|
-
json
|
|
3422
|
-
);
|
|
3423
|
-
if (typeof res === "string") return true;
|
|
3424
|
-
return (res.messages ?? []).length > 0;
|
|
3425
|
-
}
|
|
3426
|
-
async function listSlackDms(callProxy, args) {
|
|
3427
|
-
const res = await listAllConversations(callProxy, "im,mpim");
|
|
3428
|
-
if (typeof res === "string") return res;
|
|
3429
|
-
const getAuthUserId = makeGetAuthUserId(callProxy);
|
|
3430
|
-
const getUsersDirectory = makeGetUsersDirectory(callProxy);
|
|
3431
|
-
const dmNameCache = /* @__PURE__ */ new Map();
|
|
3432
|
-
const buildListing = async (convs) => {
|
|
3433
|
-
const listing = { direct_messages: [], group_dms: [] };
|
|
3434
|
-
for (const conv of convs) {
|
|
3435
|
-
if (conv.is_mpim) {
|
|
3436
|
-
const [directory, selfId] = await Promise.all([getUsersDirectory(), getAuthUserId()]);
|
|
3437
|
-
const members = groupDmMembers(conv.name, directory, selfId) ?? formatGroupDmLabel(conv.name, directory, selfId);
|
|
3438
|
-
listing.group_dms.push({ id: conv.id, members });
|
|
3439
|
-
continue;
|
|
3440
|
-
}
|
|
3441
|
-
const name = await labelForChannel(
|
|
3442
|
-
callProxy,
|
|
3443
|
-
conv,
|
|
3444
|
-
dmNameCache,
|
|
3445
|
-
getAuthUserId,
|
|
3446
|
-
getUsersDirectory
|
|
3447
|
-
);
|
|
3448
|
-
listing.direct_messages.push({ id: conv.id, name });
|
|
3449
|
-
}
|
|
3450
|
-
return listing;
|
|
3451
|
-
};
|
|
3452
|
-
const withUserRef = (args.with_user ?? "").trim();
|
|
3453
|
-
if (withUserRef) {
|
|
3454
|
-
const targetId = await resolveSlackUserId(withUserRef, getAuthUserId, getUsersDirectory);
|
|
3455
|
-
if (!targetId) return `Error: couldn't find a Slack user matching "${withUserRef}".`;
|
|
3456
|
-
const directory = await getUsersDirectory();
|
|
3457
|
-
const targetHandle = directory.byId.get(targetId)?.name?.toLowerCase();
|
|
3458
|
-
const matches = res.filter((conv) => {
|
|
3459
|
-
if (conv.is_mpim) {
|
|
3460
|
-
return targetHandle ? parseMpdmHandles(conv.name).some((h) => h.toLowerCase() === targetHandle) : false;
|
|
3461
|
-
}
|
|
3462
|
-
return conv.user === targetId;
|
|
3463
|
-
});
|
|
3464
|
-
const targetLimit = clampLimit(args.limit, matches.length, 1, matches.length);
|
|
3465
|
-
const listing = await buildListing(matches.slice(0, targetLimit));
|
|
3466
|
-
if (listing.direct_messages.length === 0) {
|
|
3467
|
-
const openedId = await openSlackDm(callProxy, targetId);
|
|
3468
|
-
if (openedId) {
|
|
3469
|
-
const surface = listing.group_dms.length === 0 || await dmHasMessages(callProxy, openedId);
|
|
3470
|
-
if (surface) {
|
|
3471
|
-
const counterparty = directory.byId.get(targetId);
|
|
3472
|
-
listing.direct_messages.push({
|
|
3473
|
-
id: openedId,
|
|
3474
|
-
name: counterparty ? displayNameForUser(counterparty) : targetId
|
|
3475
|
-
});
|
|
3476
|
-
}
|
|
3477
|
-
}
|
|
3478
|
-
}
|
|
3479
|
-
return listing;
|
|
3480
|
-
}
|
|
3481
|
-
const limit = clampLimit(args.limit, 5, 1, MAX_DM_PROBES);
|
|
3482
|
-
if (res.length > MAX_DM_PROBES) return SLACK_PENDING_APPROVAL_NOTE;
|
|
3483
|
-
const withTs = [];
|
|
3484
|
-
const withoutTs = [];
|
|
3485
|
-
for (const conv of res) {
|
|
3486
|
-
const { status, json } = await callProxy("/conversations.history", {
|
|
3487
|
-
channel: conv.id,
|
|
3488
|
-
limit: 1
|
|
3489
|
-
});
|
|
3490
|
-
const body = json ?? null;
|
|
3491
|
-
if (isRateLimited(status, body)) return SLACK_PENDING_APPROVAL_NOTE;
|
|
3492
|
-
if (status < 200 || status >= 300 || !body || body.ok === false) {
|
|
3493
|
-
withoutTs.push(conv);
|
|
3494
|
-
continue;
|
|
3495
|
-
}
|
|
3496
|
-
const messages = body.messages ?? [];
|
|
3497
|
-
if (messages.length === 0) continue;
|
|
3498
|
-
withTs.push({ conv, lastTs: Number(messages[0].ts) });
|
|
3499
|
-
}
|
|
3500
|
-
withTs.sort((a, b) => b.lastTs - a.lastTs);
|
|
3501
|
-
const ordered = [...withTs.map((x) => x.conv), ...withoutTs];
|
|
3502
|
-
return buildListing(ordered.slice(0, limit));
|
|
3503
|
-
}
|
|
3504
3333
|
var MAX_SEARCH_CHANNELS = 8;
|
|
3505
3334
|
var SEARCH_HISTORY_LIMIT = 15;
|
|
3506
|
-
var MAX_CONVERSATIONS_PAGES = 10;
|
|
3507
|
-
async function listAllConversations(callProxy, types) {
|
|
3508
|
-
const all = [];
|
|
3509
|
-
let cursor = "";
|
|
3510
|
-
for (let page = 0; page < MAX_CONVERSATIONS_PAGES; page++) {
|
|
3511
|
-
const query = {
|
|
3512
|
-
limit: 1e3,
|
|
3513
|
-
exclude_archived: "true",
|
|
3514
|
-
types
|
|
3515
|
-
};
|
|
3516
|
-
if (cursor) query.cursor = cursor;
|
|
3517
|
-
const res = await callSlack(
|
|
3518
|
-
callProxy,
|
|
3519
|
-
"/conversations.list",
|
|
3520
|
-
query
|
|
3521
|
-
);
|
|
3522
|
-
if (typeof res === "string") {
|
|
3523
|
-
if (page === 0) return res;
|
|
3524
|
-
break;
|
|
3525
|
-
}
|
|
3526
|
-
all.push(...res.channels ?? []);
|
|
3527
|
-
const next = res.response_metadata?.next_cursor;
|
|
3528
|
-
if (!next) break;
|
|
3529
|
-
cursor = next;
|
|
3530
|
-
}
|
|
3531
|
-
return all;
|
|
3532
|
-
}
|
|
3533
|
-
async function resolveChannelId(callProxy, ref) {
|
|
3534
|
-
const trimmed = ref.trim().replace(/^#/, "");
|
|
3535
|
-
if (SLACK_CHANNEL_ID_RE.test(trimmed)) return { id: trimmed };
|
|
3536
|
-
const channels = await listAllConversations(callProxy, "public_channel,private_channel");
|
|
3537
|
-
if (typeof channels === "string") return channels;
|
|
3538
|
-
const match = channels.find((c) => c.name?.toLowerCase() === trimmed.toLowerCase());
|
|
3539
|
-
if (!match) {
|
|
3540
|
-
return `Error: no Slack channel named "${ref}" in this workspace (checked the channels you're a member of).`;
|
|
3541
|
-
}
|
|
3542
|
-
return { id: match.id };
|
|
3543
|
-
}
|
|
3544
3335
|
function interleaveChannelsAndDms(conversations) {
|
|
3545
3336
|
const channels = conversations.filter((c) => !c.is_im && !c.is_mpim);
|
|
3546
3337
|
const dms = conversations.filter((c) => c.is_im || c.is_mpim);
|
|
@@ -3556,40 +3347,8 @@ function messageMatchesQuery(text, terms) {
|
|
|
3556
3347
|
const haystack = text.toLowerCase();
|
|
3557
3348
|
return terms.every((term) => haystack.includes(term));
|
|
3558
3349
|
}
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
function parseMpdmHandles(mpimName) {
|
|
3562
|
-
if (!mpimName) return [];
|
|
3563
|
-
const match = MPDM_NAME_RE.exec(mpimName);
|
|
3564
|
-
return match ? match[1].split("--") : [];
|
|
3565
|
-
}
|
|
3566
|
-
function groupDmMembers(mpimName, directory, selfId) {
|
|
3567
|
-
const handles = parseMpdmHandles(mpimName);
|
|
3568
|
-
if (handles.length === 0) return null;
|
|
3569
|
-
const selfHandle = selfId ? directory.byId.get(selfId)?.name?.toLowerCase() : void 0;
|
|
3570
|
-
const names = [];
|
|
3571
|
-
for (const handle of handles) {
|
|
3572
|
-
const key = handle.toLowerCase();
|
|
3573
|
-
if (selfHandle && key === selfHandle) continue;
|
|
3574
|
-
const member = directory.byHandle.get(key);
|
|
3575
|
-
names.push(member ? displayNameForUser(member) : handle);
|
|
3576
|
-
}
|
|
3577
|
-
if (names.length === 0) return null;
|
|
3578
|
-
const shown = names.slice(0, MAX_GROUP_DM_NAMES);
|
|
3579
|
-
const extra = names.length - shown.length;
|
|
3580
|
-
return `${shown.join(", ")}${extra > 0 ? `, +${extra} more` : ""}`;
|
|
3581
|
-
}
|
|
3582
|
-
function formatGroupDmLabel(mpimName, directory, selfId) {
|
|
3583
|
-
if (!mpimName) return "Group DM";
|
|
3584
|
-
if (parseMpdmHandles(mpimName).length === 0) return mpimName;
|
|
3585
|
-
const members = groupDmMembers(mpimName, directory, selfId);
|
|
3586
|
-
return members === null ? "Group DM" : `Group DM with ${members}`;
|
|
3587
|
-
}
|
|
3588
|
-
async function labelForChannel(callProxy, channel, dmNameCache, getAuthUserId, getUsersDirectory) {
|
|
3589
|
-
if (channel.is_mpim) {
|
|
3590
|
-
const [directory2, selfId] = await Promise.all([getUsersDirectory(), getAuthUserId()]);
|
|
3591
|
-
return formatGroupDmLabel(channel.name, directory2, selfId);
|
|
3592
|
-
}
|
|
3350
|
+
async function labelForChannel(callProxy, channel, dmNameCache, getAuthUserId) {
|
|
3351
|
+
if (channel.is_mpim) return "Group DM";
|
|
3593
3352
|
if (!channel.is_im) return channel.name ?? channel.id;
|
|
3594
3353
|
const otherId = channel.user;
|
|
3595
3354
|
if (!otherId) return channel.id;
|
|
@@ -3597,130 +3356,72 @@ async function labelForChannel(callProxy, channel, dmNameCache, getAuthUserId, g
|
|
|
3597
3356
|
if (authUserId && otherId === authUserId) return "Direct message";
|
|
3598
3357
|
const cached = dmNameCache.get(otherId);
|
|
3599
3358
|
if (cached) return `DM with ${cached}`;
|
|
3600
|
-
const directory = await getUsersDirectory();
|
|
3601
|
-
const known = directory.byId.get(otherId);
|
|
3602
|
-
if (known) {
|
|
3603
|
-
const name2 = displayNameForUser(known);
|
|
3604
|
-
dmNameCache.set(otherId, name2);
|
|
3605
|
-
return `DM with ${name2}`;
|
|
3606
|
-
}
|
|
3607
3359
|
const info = await callSlack(callProxy, "/users.info", { user: otherId });
|
|
3608
3360
|
if (typeof info === "string" || !info.user) return channel.id;
|
|
3609
3361
|
const name = info.user.profile?.display_name || info.user.real_name || info.user.name || otherId;
|
|
3610
3362
|
dmNameCache.set(otherId, name);
|
|
3611
3363
|
return `DM with ${name}`;
|
|
3612
3364
|
}
|
|
3613
|
-
var SLACK_USER_ID_RE = /^[UW][A-Z0-9]{6,}$/;
|
|
3614
|
-
var SLACK_CHANNEL_ID_RE = /^[CDG][A-Z0-9]{6,}$/;
|
|
3615
|
-
var SELF_REFS = /* @__PURE__ */ new Set(["me", "myself", "self", "i"]);
|
|
3616
|
-
async function resolveSlackUserId(ref, getAuthUserId, getUsersDirectory) {
|
|
3617
|
-
const trimmed = ref.trim();
|
|
3618
|
-
if (!trimmed) return null;
|
|
3619
|
-
if (SELF_REFS.has(trimmed.toLowerCase())) return getAuthUserId();
|
|
3620
|
-
if (SLACK_USER_ID_RE.test(trimmed)) return trimmed;
|
|
3621
|
-
const needle = trimmed.replace(/^@/, "").toLowerCase();
|
|
3622
|
-
if (!needle) return null;
|
|
3623
|
-
const { members } = await getUsersDirectory();
|
|
3624
|
-
const fieldsOf = (u) => [u.name, u.real_name, u.profile?.display_name].filter((f) => Boolean(f));
|
|
3625
|
-
const matching = (pred) => members.filter((u) => fieldsOf(u).some((f) => pred(f.toLowerCase())));
|
|
3626
|
-
const exact = matching((f) => f === needle);
|
|
3627
|
-
if (exact.length === 1) return exact[0].id;
|
|
3628
|
-
if (exact.length > 1) return null;
|
|
3629
|
-
const partial = matching((f) => f.includes(needle));
|
|
3630
|
-
return partial.length === 1 ? partial[0].id : null;
|
|
3631
|
-
}
|
|
3632
3365
|
async function searchSlackMessages(callProxy, args) {
|
|
3633
|
-
const query = (args.query ?? "").trim();
|
|
3634
|
-
const fromUserRef = (args.from_user ?? "").trim();
|
|
3635
|
-
const mentionsRef = (args.mentions ?? "").trim();
|
|
3636
|
-
if (!query && !fromUserRef && !mentionsRef) {
|
|
3637
|
-
return "Error: provide a query, from_user, or mentions to search Slack messages.";
|
|
3638
|
-
}
|
|
3639
3366
|
const count = clampLimit(args.count, 20, 1, 100);
|
|
3640
|
-
const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
3641
|
-
const
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
if (mentionsRef) {
|
|
3651
|
-
mentionId = await resolveSlackUserId(mentionsRef, getAuthUserId, getUsersDirectory);
|
|
3652
|
-
if (!mentionId) {
|
|
3653
|
-
return `Error: couldn't find a Slack user matching "${mentionsRef}" for mentions.`;
|
|
3654
|
-
}
|
|
3655
|
-
}
|
|
3656
|
-
const passes = (m) => {
|
|
3657
|
-
const text = m.text ?? "";
|
|
3658
|
-
if (terms.length > 0 && !messageMatchesQuery(text, terms)) return false;
|
|
3659
|
-
if (fromId && m.user !== fromId) return false;
|
|
3660
|
-
if (mentionId && !text.includes("<@" + mentionId)) return false;
|
|
3661
|
-
return true;
|
|
3662
|
-
};
|
|
3663
|
-
const listRes = await listAllConversations(callProxy, "public_channel,private_channel,im,mpim");
|
|
3367
|
+
const terms = args.query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
3368
|
+
const listRes = await callSlack(
|
|
3369
|
+
callProxy,
|
|
3370
|
+
"/conversations.list",
|
|
3371
|
+
{
|
|
3372
|
+
limit: 1e3,
|
|
3373
|
+
exclude_archived: "true",
|
|
3374
|
+
types: "public_channel,private_channel,im,mpim"
|
|
3375
|
+
}
|
|
3376
|
+
);
|
|
3664
3377
|
if (typeof listRes === "string") return listRes;
|
|
3665
|
-
const allChannels = listRes;
|
|
3378
|
+
const allChannels = listRes.channels ?? [];
|
|
3666
3379
|
let targets;
|
|
3667
3380
|
if (args.channel) {
|
|
3668
|
-
const
|
|
3669
|
-
|
|
3670
|
-
const found = allChannels.find(
|
|
3671
|
-
(c) => c.id === raw || c.name?.toLowerCase() === bare.toLowerCase()
|
|
3672
|
-
);
|
|
3673
|
-
if (found) {
|
|
3674
|
-
targets = [found];
|
|
3675
|
-
} else if (SLACK_CHANNEL_ID_RE.test(bare)) {
|
|
3676
|
-
targets = [{ id: bare, name: bare }];
|
|
3677
|
-
} else {
|
|
3678
|
-
return `Error: no Slack channel named "${args.channel}" in this workspace.`;
|
|
3679
|
-
}
|
|
3381
|
+
const found = allChannels.find((c) => c.id === args.channel || c.name === args.channel);
|
|
3382
|
+
targets = [found ?? { id: args.channel, name: args.channel }];
|
|
3680
3383
|
} else {
|
|
3681
3384
|
targets = interleaveChannelsAndDms(allChannels).slice(0, MAX_SEARCH_CHANNELS);
|
|
3682
3385
|
}
|
|
3386
|
+
let cachedAuthUserId;
|
|
3387
|
+
const getAuthUserId = async () => {
|
|
3388
|
+
if (cachedAuthUserId === void 0) {
|
|
3389
|
+
const auth = await callSlack(callProxy, "/auth.test");
|
|
3390
|
+
cachedAuthUserId = typeof auth === "string" ? null : auth.user_id ?? null;
|
|
3391
|
+
}
|
|
3392
|
+
return cachedAuthUserId;
|
|
3393
|
+
};
|
|
3683
3394
|
const dmNameCache = /* @__PURE__ */ new Map();
|
|
3684
3395
|
const results = [];
|
|
3685
3396
|
let rateLimited = false;
|
|
3686
3397
|
for (const channel of targets) {
|
|
3398
|
+
if (results.length >= count) break;
|
|
3687
3399
|
const { status, json } = await callProxy("/conversations.history", {
|
|
3688
3400
|
channel: channel.id,
|
|
3689
3401
|
limit: SEARCH_HISTORY_LIMIT
|
|
3690
3402
|
});
|
|
3691
3403
|
const body = json ?? null;
|
|
3692
|
-
if (
|
|
3404
|
+
if (status === 429 || body?.ok === false && body.error === "ratelimited") {
|
|
3693
3405
|
rateLimited = true;
|
|
3694
3406
|
break;
|
|
3695
3407
|
}
|
|
3696
3408
|
const connectorError = maybeConnectorError4(status, body);
|
|
3697
3409
|
if (connectorError) return connectorError;
|
|
3698
3410
|
if (status < 200 || status >= 300 || !body || body.ok === false) continue;
|
|
3699
|
-
const matched = (body.messages ?? []).filter(
|
|
3411
|
+
const matched = (body.messages ?? []).filter((m) => messageMatchesQuery(m.text ?? "", terms));
|
|
3700
3412
|
if (matched.length === 0) continue;
|
|
3701
|
-
const label = await labelForChannel(
|
|
3702
|
-
callProxy,
|
|
3703
|
-
channel,
|
|
3704
|
-
dmNameCache,
|
|
3705
|
-
getAuthUserId,
|
|
3706
|
-
getUsersDirectory
|
|
3707
|
-
);
|
|
3708
|
-
const directory = await getUsersDirectory();
|
|
3413
|
+
const label = await labelForChannel(callProxy, channel, dmNameCache, getAuthUserId);
|
|
3709
3414
|
for (const m of matched) {
|
|
3710
|
-
results.
|
|
3711
|
-
|
|
3712
|
-
user: authorName(m, directory),
|
|
3713
|
-
ts: m.ts,
|
|
3714
|
-
channel: label
|
|
3715
|
-
});
|
|
3415
|
+
if (results.length >= count) break;
|
|
3416
|
+
results.push({ text: m.text, user: m.username ?? m.user, ts: m.ts, channel: label });
|
|
3716
3417
|
}
|
|
3717
3418
|
}
|
|
3718
|
-
results.sort((a, b) => Number(b.ts) - Number(a.ts));
|
|
3719
|
-
const sliced = results.slice(0, count);
|
|
3720
3419
|
if (rateLimited) {
|
|
3721
|
-
|
|
3420
|
+
results.push({
|
|
3421
|
+
note: `Slack rate-limited channel history, so this search stopped early \u2014 returning ${results.length} match(es) found so far. Try a specific channel or ask again in a minute.`
|
|
3422
|
+
});
|
|
3722
3423
|
}
|
|
3723
|
-
return
|
|
3424
|
+
return results;
|
|
3724
3425
|
}
|
|
3725
3426
|
async function listSlackUsers(callProxy, args) {
|
|
3726
3427
|
const limit = clampLimit(args.limit, 100, 1, 1e3);
|
|
@@ -3736,46 +3437,29 @@ async function listSlackUsers(callProxy, args) {
|
|
|
3736
3437
|
}
|
|
3737
3438
|
async function getSlackChannelHistory(callProxy, args) {
|
|
3738
3439
|
const limit = clampLimit(args.limit, 20, 1, 100);
|
|
3739
|
-
const
|
|
3740
|
-
|
|
3741
|
-
const { status, json } = await callProxy("/conversations.history", {
|
|
3742
|
-
channel: resolved.id,
|
|
3743
|
-
limit
|
|
3744
|
-
});
|
|
3745
|
-
const body = json ?? null;
|
|
3746
|
-
if (isRateLimited(status, body)) return SLACK_PENDING_APPROVAL_NOTE;
|
|
3747
|
-
const res = interpretSlackResult(
|
|
3440
|
+
const res = await callSlack(
|
|
3441
|
+
callProxy,
|
|
3748
3442
|
"/conversations.history",
|
|
3749
|
-
|
|
3750
|
-
json
|
|
3443
|
+
{ channel: args.channel, limit }
|
|
3751
3444
|
);
|
|
3752
3445
|
if (typeof res === "string") return res;
|
|
3753
|
-
const directory = await makeGetUsersDirectory(callProxy)();
|
|
3754
3446
|
return (res.messages ?? []).map((m) => ({
|
|
3755
|
-
text:
|
|
3756
|
-
user:
|
|
3447
|
+
text: m.text,
|
|
3448
|
+
user: m.username ?? m.user,
|
|
3757
3449
|
ts: m.ts
|
|
3758
3450
|
}));
|
|
3759
3451
|
}
|
|
3760
3452
|
async function getSlackThreadReplies(callProxy, args) {
|
|
3761
3453
|
const limit = clampLimit(args.limit, 20, 1, 100);
|
|
3762
|
-
const
|
|
3763
|
-
|
|
3764
|
-
ts: args.ts,
|
|
3765
|
-
limit
|
|
3766
|
-
});
|
|
3767
|
-
const body = json ?? null;
|
|
3768
|
-
if (isRateLimited(status, body)) return SLACK_PENDING_APPROVAL_NOTE;
|
|
3769
|
-
const res = interpretSlackResult(
|
|
3454
|
+
const res = await callSlack(
|
|
3455
|
+
callProxy,
|
|
3770
3456
|
"/conversations.replies",
|
|
3771
|
-
|
|
3772
|
-
json
|
|
3457
|
+
{ channel: args.channel, ts: args.ts, limit }
|
|
3773
3458
|
);
|
|
3774
3459
|
if (typeof res === "string") return res;
|
|
3775
|
-
const directory = await makeGetUsersDirectory(callProxy)();
|
|
3776
3460
|
return (res.messages ?? []).map((m) => ({
|
|
3777
|
-
text:
|
|
3778
|
-
user:
|
|
3461
|
+
text: m.text,
|
|
3462
|
+
user: m.username ?? m.user,
|
|
3779
3463
|
ts: m.ts
|
|
3780
3464
|
}));
|
|
3781
3465
|
}
|
|
@@ -3810,7 +3494,7 @@ function createSlackListChannelsTool(callProxy) {
|
|
|
3810
3494
|
properties: {
|
|
3811
3495
|
limit: {
|
|
3812
3496
|
type: "number",
|
|
3813
|
-
description: "Max channels to return. Between 1 and
|
|
3497
|
+
description: "Max channels to return. Between 1 and 1000 (clamped). Defaults to 100."
|
|
3814
3498
|
}
|
|
3815
3499
|
},
|
|
3816
3500
|
required: []
|
|
@@ -3824,13 +3508,13 @@ function createSlackSearchMessagesTool(callProxy) {
|
|
|
3824
3508
|
type: "function",
|
|
3825
3509
|
function: {
|
|
3826
3510
|
name: "slack_search_messages",
|
|
3827
|
-
description: "Search recent messages across the user's Slack channels and direct messages, or within a single channel when 'channel' is given.
|
|
3511
|
+
description: "Search recent messages for text across the user's Slack channels and direct messages, or within a single channel when 'channel' is given. Matches messages containing all of the query words. Only recent history is scanned (a bounded set of conversations), so this surfaces recent mentions rather than the full archive.",
|
|
3828
3512
|
parameters: {
|
|
3829
3513
|
type: "object",
|
|
3830
3514
|
properties: {
|
|
3831
3515
|
query: {
|
|
3832
3516
|
type: "string",
|
|
3833
|
-
description: "
|
|
3517
|
+
description: "Words to look for. A message matches when its text contains all of them (case-insensitive)."
|
|
3834
3518
|
},
|
|
3835
3519
|
count: {
|
|
3836
3520
|
type: "number",
|
|
@@ -3839,52 +3523,15 @@ function createSlackSearchMessagesTool(callProxy) {
|
|
|
3839
3523
|
channel: {
|
|
3840
3524
|
type: "string",
|
|
3841
3525
|
description: "Optional channel id or name to search within. Omit to search across your channels."
|
|
3842
|
-
},
|
|
3843
|
-
from_user: {
|
|
3844
|
-
type: "string",
|
|
3845
|
-
description: "Optional. The message author to filter by, as a Slack user id or a name/handle."
|
|
3846
|
-
},
|
|
3847
|
-
mentions: {
|
|
3848
|
-
type: "string",
|
|
3849
|
-
description: 'Optional. Keep only messages that @-mention this person, as a user id, a name/handle, or "me" for yourself.'
|
|
3850
3526
|
}
|
|
3851
3527
|
},
|
|
3852
|
-
required: []
|
|
3528
|
+
required: ["query"]
|
|
3853
3529
|
}
|
|
3854
3530
|
},
|
|
3855
3531
|
executor: async (args) => searchSlackMessages(callProxy, {
|
|
3856
3532
|
query: readString(args.query),
|
|
3857
3533
|
count: args.count,
|
|
3858
|
-
channel: typeof args.channel === "string" ? args.channel : void 0
|
|
3859
|
-
from_user: typeof args.from_user === "string" ? args.from_user : void 0,
|
|
3860
|
-
mentions: typeof args.mentions === "string" ? args.mentions : void 0
|
|
3861
|
-
})
|
|
3862
|
-
};
|
|
3863
|
-
}
|
|
3864
|
-
function createSlackListDmsTool(callProxy) {
|
|
3865
|
-
return {
|
|
3866
|
-
type: "function",
|
|
3867
|
-
function: {
|
|
3868
|
-
name: "slack_list_dms",
|
|
3869
|
-
description: "List the user's Slack direct messages and group DMs, or find the DM with a specific person. Returns two separate lists: 'direct_messages' (1:1 conversations, each with 'name' = the other person) and 'group_dms' (group conversations, each with 'members' = the member names). When showing these to the user, present them as TWO separate bulleted lists -- a 'Direct messages' list (by the other person's name) and a 'Group DMs' list (by the member names) -- by name only, and never show the conversation ids. To show or read the conversation with one person, call this with with_user=<name or id> to get that conversation's id, then call slack_get_channel_history with that id to read the messages. For the latest message or recent messages from a specific person, the flow is: call this with with_user, take the returned id, then call slack_get_channel_history on it (use limit: 1 for just the last message). Do NOT use slack_search_messages to find a person's DM conversation or to read their latest message -- use with_user here instead. Listing all DMs (no with_user) returns the 5 MOST RECENT by default (most recent first, like the Slack sidebar, with empty conversations excluded), split across 'direct_messages' and 'group_dms'; pass a larger 'limit' to get more. The conversation id is only for passing to slack_get_channel_history to read a conversation.",
|
|
3870
|
-
parameters: {
|
|
3871
|
-
type: "object",
|
|
3872
|
-
properties: {
|
|
3873
|
-
limit: {
|
|
3874
|
-
type: "number",
|
|
3875
|
-
description: "Max DMs to return, default 5, up to 50."
|
|
3876
|
-
},
|
|
3877
|
-
with_user: {
|
|
3878
|
-
type: "string",
|
|
3879
|
-
description: "Optional. Return only the DM(s) with this person, as a Slack user id or a name/handle. Use this to find and read the DM with a specific person. Works even for a DM that isn't currently open -- it will open/resume the conversation to read it."
|
|
3880
|
-
}
|
|
3881
|
-
},
|
|
3882
|
-
required: []
|
|
3883
|
-
}
|
|
3884
|
-
},
|
|
3885
|
-
executor: async (args) => listSlackDms(callProxy, {
|
|
3886
|
-
limit: args.limit,
|
|
3887
|
-
with_user: typeof args.with_user === "string" ? args.with_user : void 0
|
|
3534
|
+
channel: typeof args.channel === "string" ? args.channel : void 0
|
|
3888
3535
|
})
|
|
3889
3536
|
};
|
|
3890
3537
|
}
|
|
@@ -3913,7 +3560,7 @@ function createSlackGetChannelHistoryTool(callProxy) {
|
|
|
3913
3560
|
type: "function",
|
|
3914
3561
|
function: {
|
|
3915
3562
|
name: "slack_get_channel_history",
|
|
3916
|
-
description: "Fetch recent messages from a single Slack channel by id. Best-effort and heavily rate-limited (~1 request per minute for the app), so use it sparingly for a specific channel.
|
|
3563
|
+
description: "Fetch recent messages from a single Slack channel by id. Best-effort and heavily rate-limited (~1 request per minute for the app), so use it sparingly for a specific channel.",
|
|
3917
3564
|
parameters: {
|
|
3918
3565
|
type: "object",
|
|
3919
3566
|
properties: {
|
|
@@ -4003,7 +3650,6 @@ function createSlackTools(callProxy) {
|
|
|
4003
3650
|
return {
|
|
4004
3651
|
slack_get_me: createSlackGetMeTool(callProxy),
|
|
4005
3652
|
slack_list_channels: createSlackListChannelsTool(callProxy),
|
|
4006
|
-
slack_list_dms: createSlackListDmsTool(callProxy),
|
|
4007
3653
|
slack_search_messages: createSlackSearchMessagesTool(callProxy),
|
|
4008
3654
|
slack_list_users: createSlackListUsersTool(callProxy),
|
|
4009
3655
|
slack_get_channel_history: createSlackGetChannelHistoryTool(callProxy),
|