@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.cjs
CHANGED
|
@@ -3395,7 +3395,6 @@ function createDropboxTools(getToken, requestAccess) {
|
|
|
3395
3395
|
|
|
3396
3396
|
// src/tools/slack.ts
|
|
3397
3397
|
var SLACK_PROVIDER = "slack";
|
|
3398
|
-
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.";
|
|
3399
3398
|
var AUTH_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
3400
3399
|
"not_authed",
|
|
3401
3400
|
"invalid_auth",
|
|
@@ -3419,10 +3418,8 @@ function maybeConnectorError4(status, body) {
|
|
|
3419
3418
|
}
|
|
3420
3419
|
return null;
|
|
3421
3420
|
}
|
|
3422
|
-
function
|
|
3423
|
-
|
|
3424
|
-
}
|
|
3425
|
-
function interpretSlackResult(path, status, json) {
|
|
3421
|
+
async function callSlack(callProxy, path, query, requestBody) {
|
|
3422
|
+
const { status, json } = await callProxy(path, query, requestBody);
|
|
3426
3423
|
const body = json ?? null;
|
|
3427
3424
|
if (status < 200 || status >= 300) {
|
|
3428
3425
|
const connectorError = maybeConnectorError4(status, body);
|
|
@@ -3436,10 +3433,6 @@ function interpretSlackResult(path, status, json) {
|
|
|
3436
3433
|
}
|
|
3437
3434
|
return body;
|
|
3438
3435
|
}
|
|
3439
|
-
async function callSlack(callProxy, path, query, requestBody) {
|
|
3440
|
-
const { status, json } = await callProxy(path, query, requestBody);
|
|
3441
|
-
return interpretSlackResult(path, status, json);
|
|
3442
|
-
}
|
|
3443
3436
|
function readString(raw) {
|
|
3444
3437
|
return typeof raw === "string" ? raw : "";
|
|
3445
3438
|
}
|
|
@@ -3448,70 +3441,6 @@ function clampLimit(raw, fallback, min, max) {
|
|
|
3448
3441
|
const safe = typeof num === "number" && Number.isFinite(num) ? num : fallback;
|
|
3449
3442
|
return Math.min(max, Math.max(min, safe));
|
|
3450
3443
|
}
|
|
3451
|
-
function makeGetAuthUserId(callProxy) {
|
|
3452
|
-
let cached;
|
|
3453
|
-
return async () => {
|
|
3454
|
-
if (cached === void 0) {
|
|
3455
|
-
const auth = await callSlack(callProxy, "/auth.test");
|
|
3456
|
-
cached = typeof auth === "string" ? null : auth.user_id ?? null;
|
|
3457
|
-
}
|
|
3458
|
-
return cached;
|
|
3459
|
-
};
|
|
3460
|
-
}
|
|
3461
|
-
function displayNameForUser(user) {
|
|
3462
|
-
return user.profile?.display_name || user.real_name || user.name || user.id;
|
|
3463
|
-
}
|
|
3464
|
-
function authorName(m, directory) {
|
|
3465
|
-
const known = m.user ? directory.byId.get(m.user) : void 0;
|
|
3466
|
-
return known && displayNameForUser(known) || m.username || m.user || "";
|
|
3467
|
-
}
|
|
3468
|
-
var USER_MENTION_RE = /<@([UW][A-Z0-9]+)(?:\|([^>]+))?>/g;
|
|
3469
|
-
var CHANNEL_MENTION_RE = /<#(C[A-Z0-9]+)(?:\|([^>]+))?>/g;
|
|
3470
|
-
function humanizeSlackText(text, directory) {
|
|
3471
|
-
return text.replace(USER_MENTION_RE, (_match, id, handle) => {
|
|
3472
|
-
const known = directory.byId.get(id);
|
|
3473
|
-
return `@${known && displayNameForUser(known) || handle || id}`;
|
|
3474
|
-
}).replace(
|
|
3475
|
-
CHANNEL_MENTION_RE,
|
|
3476
|
-
(match, _id, name) => name ? `#${name}` : match
|
|
3477
|
-
);
|
|
3478
|
-
}
|
|
3479
|
-
var MAX_USERS_PAGES = 10;
|
|
3480
|
-
async function listAllUsers(callProxy) {
|
|
3481
|
-
const all = [];
|
|
3482
|
-
let cursor = "";
|
|
3483
|
-
for (let page = 0; page < MAX_USERS_PAGES; page++) {
|
|
3484
|
-
const query = { limit: 1e3 };
|
|
3485
|
-
if (cursor) query.cursor = cursor;
|
|
3486
|
-
const res = await callSlack(callProxy, "/users.list", query);
|
|
3487
|
-
if (typeof res === "string") {
|
|
3488
|
-
if (page === 0) return res;
|
|
3489
|
-
break;
|
|
3490
|
-
}
|
|
3491
|
-
all.push(...res.members ?? []);
|
|
3492
|
-
const next = res.response_metadata?.next_cursor;
|
|
3493
|
-
if (!next) break;
|
|
3494
|
-
cursor = next;
|
|
3495
|
-
}
|
|
3496
|
-
return all;
|
|
3497
|
-
}
|
|
3498
|
-
function makeGetUsersDirectory(callProxy) {
|
|
3499
|
-
let cached;
|
|
3500
|
-
return async () => {
|
|
3501
|
-
if (cached === void 0) {
|
|
3502
|
-
const res = await listAllUsers(callProxy);
|
|
3503
|
-
const members = (typeof res === "string" ? [] : res).filter((u) => !u.deleted);
|
|
3504
|
-
const byId = /* @__PURE__ */ new Map();
|
|
3505
|
-
const byHandle = /* @__PURE__ */ new Map();
|
|
3506
|
-
for (const user of members) {
|
|
3507
|
-
byId.set(user.id, user);
|
|
3508
|
-
if (user.name) byHandle.set(user.name.toLowerCase(), user);
|
|
3509
|
-
}
|
|
3510
|
-
cached = { members, byId, byHandle };
|
|
3511
|
-
}
|
|
3512
|
-
return cached;
|
|
3513
|
-
};
|
|
3514
|
-
}
|
|
3515
3444
|
async function getSlackMe(callProxy) {
|
|
3516
3445
|
const auth = await callSlack(callProxy, "/auth.test");
|
|
3517
3446
|
if (typeof auth === "string") return auth;
|
|
@@ -3534,10 +3463,14 @@ async function getSlackMe(callProxy) {
|
|
|
3534
3463
|
};
|
|
3535
3464
|
}
|
|
3536
3465
|
async function listSlackChannels(callProxy, args) {
|
|
3537
|
-
const limit = clampLimit(args.limit,
|
|
3538
|
-
const res = await
|
|
3466
|
+
const limit = clampLimit(args.limit, 100, 1, 1e3);
|
|
3467
|
+
const res = await callSlack(callProxy, "/conversations.list", {
|
|
3468
|
+
limit,
|
|
3469
|
+
exclude_archived: "true",
|
|
3470
|
+
types: "public_channel,private_channel"
|
|
3471
|
+
});
|
|
3539
3472
|
if (typeof res === "string") return res;
|
|
3540
|
-
return res.
|
|
3473
|
+
return (res.channels ?? []).map((c) => ({
|
|
3541
3474
|
id: c.id,
|
|
3542
3475
|
name: c.name,
|
|
3543
3476
|
is_private: c.is_private,
|
|
@@ -3546,150 +3479,8 @@ async function listSlackChannels(callProxy, args) {
|
|
|
3546
3479
|
purpose: c.purpose?.value
|
|
3547
3480
|
}));
|
|
3548
3481
|
}
|
|
3549
|
-
var MAX_DM_PROBES = 50;
|
|
3550
|
-
async function openSlackDm(callProxy, userId) {
|
|
3551
|
-
const res = await callSlack(
|
|
3552
|
-
callProxy,
|
|
3553
|
-
"/conversations.open",
|
|
3554
|
-
void 0,
|
|
3555
|
-
{ users: userId }
|
|
3556
|
-
);
|
|
3557
|
-
if (typeof res === "string") return null;
|
|
3558
|
-
return res.channel?.id ?? null;
|
|
3559
|
-
}
|
|
3560
|
-
async function dmHasMessages(callProxy, channelId) {
|
|
3561
|
-
const { status, json } = await callProxy("/conversations.history", {
|
|
3562
|
-
channel: channelId,
|
|
3563
|
-
limit: 1
|
|
3564
|
-
});
|
|
3565
|
-
const body = json ?? null;
|
|
3566
|
-
if (isRateLimited(status, body)) return true;
|
|
3567
|
-
const res = interpretSlackResult(
|
|
3568
|
-
"/conversations.history",
|
|
3569
|
-
status,
|
|
3570
|
-
json
|
|
3571
|
-
);
|
|
3572
|
-
if (typeof res === "string") return true;
|
|
3573
|
-
return (res.messages ?? []).length > 0;
|
|
3574
|
-
}
|
|
3575
|
-
async function listSlackDms(callProxy, args) {
|
|
3576
|
-
const res = await listAllConversations(callProxy, "im,mpim");
|
|
3577
|
-
if (typeof res === "string") return res;
|
|
3578
|
-
const getAuthUserId = makeGetAuthUserId(callProxy);
|
|
3579
|
-
const getUsersDirectory = makeGetUsersDirectory(callProxy);
|
|
3580
|
-
const dmNameCache = /* @__PURE__ */ new Map();
|
|
3581
|
-
const buildListing = async (convs) => {
|
|
3582
|
-
const listing = { direct_messages: [], group_dms: [] };
|
|
3583
|
-
for (const conv of convs) {
|
|
3584
|
-
if (conv.is_mpim) {
|
|
3585
|
-
const [directory, selfId] = await Promise.all([getUsersDirectory(), getAuthUserId()]);
|
|
3586
|
-
const members = groupDmMembers(conv.name, directory, selfId) ?? formatGroupDmLabel(conv.name, directory, selfId);
|
|
3587
|
-
listing.group_dms.push({ id: conv.id, members });
|
|
3588
|
-
continue;
|
|
3589
|
-
}
|
|
3590
|
-
const name = await labelForChannel(
|
|
3591
|
-
callProxy,
|
|
3592
|
-
conv,
|
|
3593
|
-
dmNameCache,
|
|
3594
|
-
getAuthUserId,
|
|
3595
|
-
getUsersDirectory
|
|
3596
|
-
);
|
|
3597
|
-
listing.direct_messages.push({ id: conv.id, name });
|
|
3598
|
-
}
|
|
3599
|
-
return listing;
|
|
3600
|
-
};
|
|
3601
|
-
const withUserRef = (args.with_user ?? "").trim();
|
|
3602
|
-
if (withUserRef) {
|
|
3603
|
-
const targetId = await resolveSlackUserId(withUserRef, getAuthUserId, getUsersDirectory);
|
|
3604
|
-
if (!targetId) return `Error: couldn't find a Slack user matching "${withUserRef}".`;
|
|
3605
|
-
const directory = await getUsersDirectory();
|
|
3606
|
-
const targetHandle = directory.byId.get(targetId)?.name?.toLowerCase();
|
|
3607
|
-
const matches = res.filter((conv) => {
|
|
3608
|
-
if (conv.is_mpim) {
|
|
3609
|
-
return targetHandle ? parseMpdmHandles(conv.name).some((h) => h.toLowerCase() === targetHandle) : false;
|
|
3610
|
-
}
|
|
3611
|
-
return conv.user === targetId;
|
|
3612
|
-
});
|
|
3613
|
-
const targetLimit = clampLimit(args.limit, matches.length, 1, matches.length);
|
|
3614
|
-
const listing = await buildListing(matches.slice(0, targetLimit));
|
|
3615
|
-
if (listing.direct_messages.length === 0) {
|
|
3616
|
-
const openedId = await openSlackDm(callProxy, targetId);
|
|
3617
|
-
if (openedId) {
|
|
3618
|
-
const surface = listing.group_dms.length === 0 || await dmHasMessages(callProxy, openedId);
|
|
3619
|
-
if (surface) {
|
|
3620
|
-
const counterparty = directory.byId.get(targetId);
|
|
3621
|
-
listing.direct_messages.push({
|
|
3622
|
-
id: openedId,
|
|
3623
|
-
name: counterparty ? displayNameForUser(counterparty) : targetId
|
|
3624
|
-
});
|
|
3625
|
-
}
|
|
3626
|
-
}
|
|
3627
|
-
}
|
|
3628
|
-
return listing;
|
|
3629
|
-
}
|
|
3630
|
-
const limit = clampLimit(args.limit, 5, 1, MAX_DM_PROBES);
|
|
3631
|
-
if (res.length > MAX_DM_PROBES) return SLACK_PENDING_APPROVAL_NOTE;
|
|
3632
|
-
const withTs = [];
|
|
3633
|
-
const withoutTs = [];
|
|
3634
|
-
for (const conv of res) {
|
|
3635
|
-
const { status, json } = await callProxy("/conversations.history", {
|
|
3636
|
-
channel: conv.id,
|
|
3637
|
-
limit: 1
|
|
3638
|
-
});
|
|
3639
|
-
const body = json ?? null;
|
|
3640
|
-
if (isRateLimited(status, body)) return SLACK_PENDING_APPROVAL_NOTE;
|
|
3641
|
-
if (status < 200 || status >= 300 || !body || body.ok === false) {
|
|
3642
|
-
withoutTs.push(conv);
|
|
3643
|
-
continue;
|
|
3644
|
-
}
|
|
3645
|
-
const messages = body.messages ?? [];
|
|
3646
|
-
if (messages.length === 0) continue;
|
|
3647
|
-
withTs.push({ conv, lastTs: Number(messages[0].ts) });
|
|
3648
|
-
}
|
|
3649
|
-
withTs.sort((a, b) => b.lastTs - a.lastTs);
|
|
3650
|
-
const ordered = [...withTs.map((x) => x.conv), ...withoutTs];
|
|
3651
|
-
return buildListing(ordered.slice(0, limit));
|
|
3652
|
-
}
|
|
3653
3482
|
var MAX_SEARCH_CHANNELS = 8;
|
|
3654
3483
|
var SEARCH_HISTORY_LIMIT = 15;
|
|
3655
|
-
var MAX_CONVERSATIONS_PAGES = 10;
|
|
3656
|
-
async function listAllConversations(callProxy, types) {
|
|
3657
|
-
const all = [];
|
|
3658
|
-
let cursor = "";
|
|
3659
|
-
for (let page = 0; page < MAX_CONVERSATIONS_PAGES; page++) {
|
|
3660
|
-
const query = {
|
|
3661
|
-
limit: 1e3,
|
|
3662
|
-
exclude_archived: "true",
|
|
3663
|
-
types
|
|
3664
|
-
};
|
|
3665
|
-
if (cursor) query.cursor = cursor;
|
|
3666
|
-
const res = await callSlack(
|
|
3667
|
-
callProxy,
|
|
3668
|
-
"/conversations.list",
|
|
3669
|
-
query
|
|
3670
|
-
);
|
|
3671
|
-
if (typeof res === "string") {
|
|
3672
|
-
if (page === 0) return res;
|
|
3673
|
-
break;
|
|
3674
|
-
}
|
|
3675
|
-
all.push(...res.channels ?? []);
|
|
3676
|
-
const next = res.response_metadata?.next_cursor;
|
|
3677
|
-
if (!next) break;
|
|
3678
|
-
cursor = next;
|
|
3679
|
-
}
|
|
3680
|
-
return all;
|
|
3681
|
-
}
|
|
3682
|
-
async function resolveChannelId(callProxy, ref) {
|
|
3683
|
-
const trimmed = ref.trim().replace(/^#/, "");
|
|
3684
|
-
if (SLACK_CHANNEL_ID_RE.test(trimmed)) return { id: trimmed };
|
|
3685
|
-
const channels = await listAllConversations(callProxy, "public_channel,private_channel");
|
|
3686
|
-
if (typeof channels === "string") return channels;
|
|
3687
|
-
const match = channels.find((c) => c.name?.toLowerCase() === trimmed.toLowerCase());
|
|
3688
|
-
if (!match) {
|
|
3689
|
-
return `Error: no Slack channel named "${ref}" in this workspace (checked the channels you're a member of).`;
|
|
3690
|
-
}
|
|
3691
|
-
return { id: match.id };
|
|
3692
|
-
}
|
|
3693
3484
|
function interleaveChannelsAndDms(conversations) {
|
|
3694
3485
|
const channels = conversations.filter((c) => !c.is_im && !c.is_mpim);
|
|
3695
3486
|
const dms = conversations.filter((c) => c.is_im || c.is_mpim);
|
|
@@ -3705,40 +3496,8 @@ function messageMatchesQuery(text, terms) {
|
|
|
3705
3496
|
const haystack = text.toLowerCase();
|
|
3706
3497
|
return terms.every((term) => haystack.includes(term));
|
|
3707
3498
|
}
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
function parseMpdmHandles(mpimName) {
|
|
3711
|
-
if (!mpimName) return [];
|
|
3712
|
-
const match = MPDM_NAME_RE.exec(mpimName);
|
|
3713
|
-
return match ? match[1].split("--") : [];
|
|
3714
|
-
}
|
|
3715
|
-
function groupDmMembers(mpimName, directory, selfId) {
|
|
3716
|
-
const handles = parseMpdmHandles(mpimName);
|
|
3717
|
-
if (handles.length === 0) return null;
|
|
3718
|
-
const selfHandle = selfId ? directory.byId.get(selfId)?.name?.toLowerCase() : void 0;
|
|
3719
|
-
const names = [];
|
|
3720
|
-
for (const handle of handles) {
|
|
3721
|
-
const key = handle.toLowerCase();
|
|
3722
|
-
if (selfHandle && key === selfHandle) continue;
|
|
3723
|
-
const member = directory.byHandle.get(key);
|
|
3724
|
-
names.push(member ? displayNameForUser(member) : handle);
|
|
3725
|
-
}
|
|
3726
|
-
if (names.length === 0) return null;
|
|
3727
|
-
const shown = names.slice(0, MAX_GROUP_DM_NAMES);
|
|
3728
|
-
const extra = names.length - shown.length;
|
|
3729
|
-
return `${shown.join(", ")}${extra > 0 ? `, +${extra} more` : ""}`;
|
|
3730
|
-
}
|
|
3731
|
-
function formatGroupDmLabel(mpimName, directory, selfId) {
|
|
3732
|
-
if (!mpimName) return "Group DM";
|
|
3733
|
-
if (parseMpdmHandles(mpimName).length === 0) return mpimName;
|
|
3734
|
-
const members = groupDmMembers(mpimName, directory, selfId);
|
|
3735
|
-
return members === null ? "Group DM" : `Group DM with ${members}`;
|
|
3736
|
-
}
|
|
3737
|
-
async function labelForChannel(callProxy, channel, dmNameCache, getAuthUserId, getUsersDirectory) {
|
|
3738
|
-
if (channel.is_mpim) {
|
|
3739
|
-
const [directory2, selfId] = await Promise.all([getUsersDirectory(), getAuthUserId()]);
|
|
3740
|
-
return formatGroupDmLabel(channel.name, directory2, selfId);
|
|
3741
|
-
}
|
|
3499
|
+
async function labelForChannel(callProxy, channel, dmNameCache, getAuthUserId) {
|
|
3500
|
+
if (channel.is_mpim) return "Group DM";
|
|
3742
3501
|
if (!channel.is_im) return channel.name ?? channel.id;
|
|
3743
3502
|
const otherId = channel.user;
|
|
3744
3503
|
if (!otherId) return channel.id;
|
|
@@ -3746,130 +3505,72 @@ async function labelForChannel(callProxy, channel, dmNameCache, getAuthUserId, g
|
|
|
3746
3505
|
if (authUserId && otherId === authUserId) return "Direct message";
|
|
3747
3506
|
const cached = dmNameCache.get(otherId);
|
|
3748
3507
|
if (cached) return `DM with ${cached}`;
|
|
3749
|
-
const directory = await getUsersDirectory();
|
|
3750
|
-
const known = directory.byId.get(otherId);
|
|
3751
|
-
if (known) {
|
|
3752
|
-
const name2 = displayNameForUser(known);
|
|
3753
|
-
dmNameCache.set(otherId, name2);
|
|
3754
|
-
return `DM with ${name2}`;
|
|
3755
|
-
}
|
|
3756
3508
|
const info = await callSlack(callProxy, "/users.info", { user: otherId });
|
|
3757
3509
|
if (typeof info === "string" || !info.user) return channel.id;
|
|
3758
3510
|
const name = info.user.profile?.display_name || info.user.real_name || info.user.name || otherId;
|
|
3759
3511
|
dmNameCache.set(otherId, name);
|
|
3760
3512
|
return `DM with ${name}`;
|
|
3761
3513
|
}
|
|
3762
|
-
var SLACK_USER_ID_RE = /^[UW][A-Z0-9]{6,}$/;
|
|
3763
|
-
var SLACK_CHANNEL_ID_RE = /^[CDG][A-Z0-9]{6,}$/;
|
|
3764
|
-
var SELF_REFS = /* @__PURE__ */ new Set(["me", "myself", "self", "i"]);
|
|
3765
|
-
async function resolveSlackUserId(ref, getAuthUserId, getUsersDirectory) {
|
|
3766
|
-
const trimmed = ref.trim();
|
|
3767
|
-
if (!trimmed) return null;
|
|
3768
|
-
if (SELF_REFS.has(trimmed.toLowerCase())) return getAuthUserId();
|
|
3769
|
-
if (SLACK_USER_ID_RE.test(trimmed)) return trimmed;
|
|
3770
|
-
const needle = trimmed.replace(/^@/, "").toLowerCase();
|
|
3771
|
-
if (!needle) return null;
|
|
3772
|
-
const { members } = await getUsersDirectory();
|
|
3773
|
-
const fieldsOf = (u) => [u.name, u.real_name, u.profile?.display_name].filter((f) => Boolean(f));
|
|
3774
|
-
const matching = (pred) => members.filter((u) => fieldsOf(u).some((f) => pred(f.toLowerCase())));
|
|
3775
|
-
const exact = matching((f) => f === needle);
|
|
3776
|
-
if (exact.length === 1) return exact[0].id;
|
|
3777
|
-
if (exact.length > 1) return null;
|
|
3778
|
-
const partial = matching((f) => f.includes(needle));
|
|
3779
|
-
return partial.length === 1 ? partial[0].id : null;
|
|
3780
|
-
}
|
|
3781
3514
|
async function searchSlackMessages(callProxy, args) {
|
|
3782
|
-
const query = (args.query ?? "").trim();
|
|
3783
|
-
const fromUserRef = (args.from_user ?? "").trim();
|
|
3784
|
-
const mentionsRef = (args.mentions ?? "").trim();
|
|
3785
|
-
if (!query && !fromUserRef && !mentionsRef) {
|
|
3786
|
-
return "Error: provide a query, from_user, or mentions to search Slack messages.";
|
|
3787
|
-
}
|
|
3788
3515
|
const count = clampLimit(args.count, 20, 1, 100);
|
|
3789
|
-
const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
3790
|
-
const
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
if (mentionsRef) {
|
|
3800
|
-
mentionId = await resolveSlackUserId(mentionsRef, getAuthUserId, getUsersDirectory);
|
|
3801
|
-
if (!mentionId) {
|
|
3802
|
-
return `Error: couldn't find a Slack user matching "${mentionsRef}" for mentions.`;
|
|
3803
|
-
}
|
|
3804
|
-
}
|
|
3805
|
-
const passes = (m) => {
|
|
3806
|
-
const text = m.text ?? "";
|
|
3807
|
-
if (terms.length > 0 && !messageMatchesQuery(text, terms)) return false;
|
|
3808
|
-
if (fromId && m.user !== fromId) return false;
|
|
3809
|
-
if (mentionId && !text.includes("<@" + mentionId)) return false;
|
|
3810
|
-
return true;
|
|
3811
|
-
};
|
|
3812
|
-
const listRes = await listAllConversations(callProxy, "public_channel,private_channel,im,mpim");
|
|
3516
|
+
const terms = args.query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
3517
|
+
const listRes = await callSlack(
|
|
3518
|
+
callProxy,
|
|
3519
|
+
"/conversations.list",
|
|
3520
|
+
{
|
|
3521
|
+
limit: 1e3,
|
|
3522
|
+
exclude_archived: "true",
|
|
3523
|
+
types: "public_channel,private_channel,im,mpim"
|
|
3524
|
+
}
|
|
3525
|
+
);
|
|
3813
3526
|
if (typeof listRes === "string") return listRes;
|
|
3814
|
-
const allChannels = listRes;
|
|
3527
|
+
const allChannels = listRes.channels ?? [];
|
|
3815
3528
|
let targets;
|
|
3816
3529
|
if (args.channel) {
|
|
3817
|
-
const
|
|
3818
|
-
|
|
3819
|
-
const found = allChannels.find(
|
|
3820
|
-
(c) => c.id === raw || c.name?.toLowerCase() === bare.toLowerCase()
|
|
3821
|
-
);
|
|
3822
|
-
if (found) {
|
|
3823
|
-
targets = [found];
|
|
3824
|
-
} else if (SLACK_CHANNEL_ID_RE.test(bare)) {
|
|
3825
|
-
targets = [{ id: bare, name: bare }];
|
|
3826
|
-
} else {
|
|
3827
|
-
return `Error: no Slack channel named "${args.channel}" in this workspace.`;
|
|
3828
|
-
}
|
|
3530
|
+
const found = allChannels.find((c) => c.id === args.channel || c.name === args.channel);
|
|
3531
|
+
targets = [found ?? { id: args.channel, name: args.channel }];
|
|
3829
3532
|
} else {
|
|
3830
3533
|
targets = interleaveChannelsAndDms(allChannels).slice(0, MAX_SEARCH_CHANNELS);
|
|
3831
3534
|
}
|
|
3535
|
+
let cachedAuthUserId;
|
|
3536
|
+
const getAuthUserId = async () => {
|
|
3537
|
+
if (cachedAuthUserId === void 0) {
|
|
3538
|
+
const auth = await callSlack(callProxy, "/auth.test");
|
|
3539
|
+
cachedAuthUserId = typeof auth === "string" ? null : auth.user_id ?? null;
|
|
3540
|
+
}
|
|
3541
|
+
return cachedAuthUserId;
|
|
3542
|
+
};
|
|
3832
3543
|
const dmNameCache = /* @__PURE__ */ new Map();
|
|
3833
3544
|
const results = [];
|
|
3834
3545
|
let rateLimited = false;
|
|
3835
3546
|
for (const channel of targets) {
|
|
3547
|
+
if (results.length >= count) break;
|
|
3836
3548
|
const { status, json } = await callProxy("/conversations.history", {
|
|
3837
3549
|
channel: channel.id,
|
|
3838
3550
|
limit: SEARCH_HISTORY_LIMIT
|
|
3839
3551
|
});
|
|
3840
3552
|
const body = json ?? null;
|
|
3841
|
-
if (
|
|
3553
|
+
if (status === 429 || body?.ok === false && body.error === "ratelimited") {
|
|
3842
3554
|
rateLimited = true;
|
|
3843
3555
|
break;
|
|
3844
3556
|
}
|
|
3845
3557
|
const connectorError = maybeConnectorError4(status, body);
|
|
3846
3558
|
if (connectorError) return connectorError;
|
|
3847
3559
|
if (status < 200 || status >= 300 || !body || body.ok === false) continue;
|
|
3848
|
-
const matched = (body.messages ?? []).filter(
|
|
3560
|
+
const matched = (body.messages ?? []).filter((m) => messageMatchesQuery(m.text ?? "", terms));
|
|
3849
3561
|
if (matched.length === 0) continue;
|
|
3850
|
-
const label = await labelForChannel(
|
|
3851
|
-
callProxy,
|
|
3852
|
-
channel,
|
|
3853
|
-
dmNameCache,
|
|
3854
|
-
getAuthUserId,
|
|
3855
|
-
getUsersDirectory
|
|
3856
|
-
);
|
|
3857
|
-
const directory = await getUsersDirectory();
|
|
3562
|
+
const label = await labelForChannel(callProxy, channel, dmNameCache, getAuthUserId);
|
|
3858
3563
|
for (const m of matched) {
|
|
3859
|
-
results.
|
|
3860
|
-
|
|
3861
|
-
user: authorName(m, directory),
|
|
3862
|
-
ts: m.ts,
|
|
3863
|
-
channel: label
|
|
3864
|
-
});
|
|
3564
|
+
if (results.length >= count) break;
|
|
3565
|
+
results.push({ text: m.text, user: m.username ?? m.user, ts: m.ts, channel: label });
|
|
3865
3566
|
}
|
|
3866
3567
|
}
|
|
3867
|
-
results.sort((a, b) => Number(b.ts) - Number(a.ts));
|
|
3868
|
-
const sliced = results.slice(0, count);
|
|
3869
3568
|
if (rateLimited) {
|
|
3870
|
-
|
|
3569
|
+
results.push({
|
|
3570
|
+
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.`
|
|
3571
|
+
});
|
|
3871
3572
|
}
|
|
3872
|
-
return
|
|
3573
|
+
return results;
|
|
3873
3574
|
}
|
|
3874
3575
|
async function listSlackUsers(callProxy, args) {
|
|
3875
3576
|
const limit = clampLimit(args.limit, 100, 1, 1e3);
|
|
@@ -3885,46 +3586,29 @@ async function listSlackUsers(callProxy, args) {
|
|
|
3885
3586
|
}
|
|
3886
3587
|
async function getSlackChannelHistory(callProxy, args) {
|
|
3887
3588
|
const limit = clampLimit(args.limit, 20, 1, 100);
|
|
3888
|
-
const
|
|
3889
|
-
|
|
3890
|
-
const { status, json } = await callProxy("/conversations.history", {
|
|
3891
|
-
channel: resolved.id,
|
|
3892
|
-
limit
|
|
3893
|
-
});
|
|
3894
|
-
const body = json ?? null;
|
|
3895
|
-
if (isRateLimited(status, body)) return SLACK_PENDING_APPROVAL_NOTE;
|
|
3896
|
-
const res = interpretSlackResult(
|
|
3589
|
+
const res = await callSlack(
|
|
3590
|
+
callProxy,
|
|
3897
3591
|
"/conversations.history",
|
|
3898
|
-
|
|
3899
|
-
json
|
|
3592
|
+
{ channel: args.channel, limit }
|
|
3900
3593
|
);
|
|
3901
3594
|
if (typeof res === "string") return res;
|
|
3902
|
-
const directory = await makeGetUsersDirectory(callProxy)();
|
|
3903
3595
|
return (res.messages ?? []).map((m) => ({
|
|
3904
|
-
text:
|
|
3905
|
-
user:
|
|
3596
|
+
text: m.text,
|
|
3597
|
+
user: m.username ?? m.user,
|
|
3906
3598
|
ts: m.ts
|
|
3907
3599
|
}));
|
|
3908
3600
|
}
|
|
3909
3601
|
async function getSlackThreadReplies(callProxy, args) {
|
|
3910
3602
|
const limit = clampLimit(args.limit, 20, 1, 100);
|
|
3911
|
-
const
|
|
3912
|
-
|
|
3913
|
-
ts: args.ts,
|
|
3914
|
-
limit
|
|
3915
|
-
});
|
|
3916
|
-
const body = json ?? null;
|
|
3917
|
-
if (isRateLimited(status, body)) return SLACK_PENDING_APPROVAL_NOTE;
|
|
3918
|
-
const res = interpretSlackResult(
|
|
3603
|
+
const res = await callSlack(
|
|
3604
|
+
callProxy,
|
|
3919
3605
|
"/conversations.replies",
|
|
3920
|
-
|
|
3921
|
-
json
|
|
3606
|
+
{ channel: args.channel, ts: args.ts, limit }
|
|
3922
3607
|
);
|
|
3923
3608
|
if (typeof res === "string") return res;
|
|
3924
|
-
const directory = await makeGetUsersDirectory(callProxy)();
|
|
3925
3609
|
return (res.messages ?? []).map((m) => ({
|
|
3926
|
-
text:
|
|
3927
|
-
user:
|
|
3610
|
+
text: m.text,
|
|
3611
|
+
user: m.username ?? m.user,
|
|
3928
3612
|
ts: m.ts
|
|
3929
3613
|
}));
|
|
3930
3614
|
}
|
|
@@ -3959,7 +3643,7 @@ function createSlackListChannelsTool(callProxy) {
|
|
|
3959
3643
|
properties: {
|
|
3960
3644
|
limit: {
|
|
3961
3645
|
type: "number",
|
|
3962
|
-
description: "Max channels to return. Between 1 and
|
|
3646
|
+
description: "Max channels to return. Between 1 and 1000 (clamped). Defaults to 100."
|
|
3963
3647
|
}
|
|
3964
3648
|
},
|
|
3965
3649
|
required: []
|
|
@@ -3973,13 +3657,13 @@ function createSlackSearchMessagesTool(callProxy) {
|
|
|
3973
3657
|
type: "function",
|
|
3974
3658
|
function: {
|
|
3975
3659
|
name: "slack_search_messages",
|
|
3976
|
-
description: "Search recent messages across the user's Slack channels and direct messages, or within a single channel when 'channel' is given.
|
|
3660
|
+
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.",
|
|
3977
3661
|
parameters: {
|
|
3978
3662
|
type: "object",
|
|
3979
3663
|
properties: {
|
|
3980
3664
|
query: {
|
|
3981
3665
|
type: "string",
|
|
3982
|
-
description: "
|
|
3666
|
+
description: "Words to look for. A message matches when its text contains all of them (case-insensitive)."
|
|
3983
3667
|
},
|
|
3984
3668
|
count: {
|
|
3985
3669
|
type: "number",
|
|
@@ -3988,52 +3672,15 @@ function createSlackSearchMessagesTool(callProxy) {
|
|
|
3988
3672
|
channel: {
|
|
3989
3673
|
type: "string",
|
|
3990
3674
|
description: "Optional channel id or name to search within. Omit to search across your channels."
|
|
3991
|
-
},
|
|
3992
|
-
from_user: {
|
|
3993
|
-
type: "string",
|
|
3994
|
-
description: "Optional. The message author to filter by, as a Slack user id or a name/handle."
|
|
3995
|
-
},
|
|
3996
|
-
mentions: {
|
|
3997
|
-
type: "string",
|
|
3998
|
-
description: 'Optional. Keep only messages that @-mention this person, as a user id, a name/handle, or "me" for yourself.'
|
|
3999
3675
|
}
|
|
4000
3676
|
},
|
|
4001
|
-
required: []
|
|
3677
|
+
required: ["query"]
|
|
4002
3678
|
}
|
|
4003
3679
|
},
|
|
4004
3680
|
executor: async (args) => searchSlackMessages(callProxy, {
|
|
4005
3681
|
query: readString(args.query),
|
|
4006
3682
|
count: args.count,
|
|
4007
|
-
channel: typeof args.channel === "string" ? args.channel : void 0
|
|
4008
|
-
from_user: typeof args.from_user === "string" ? args.from_user : void 0,
|
|
4009
|
-
mentions: typeof args.mentions === "string" ? args.mentions : void 0
|
|
4010
|
-
})
|
|
4011
|
-
};
|
|
4012
|
-
}
|
|
4013
|
-
function createSlackListDmsTool(callProxy) {
|
|
4014
|
-
return {
|
|
4015
|
-
type: "function",
|
|
4016
|
-
function: {
|
|
4017
|
-
name: "slack_list_dms",
|
|
4018
|
-
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.",
|
|
4019
|
-
parameters: {
|
|
4020
|
-
type: "object",
|
|
4021
|
-
properties: {
|
|
4022
|
-
limit: {
|
|
4023
|
-
type: "number",
|
|
4024
|
-
description: "Max DMs to return, default 5, up to 50."
|
|
4025
|
-
},
|
|
4026
|
-
with_user: {
|
|
4027
|
-
type: "string",
|
|
4028
|
-
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."
|
|
4029
|
-
}
|
|
4030
|
-
},
|
|
4031
|
-
required: []
|
|
4032
|
-
}
|
|
4033
|
-
},
|
|
4034
|
-
executor: async (args) => listSlackDms(callProxy, {
|
|
4035
|
-
limit: args.limit,
|
|
4036
|
-
with_user: typeof args.with_user === "string" ? args.with_user : void 0
|
|
3683
|
+
channel: typeof args.channel === "string" ? args.channel : void 0
|
|
4037
3684
|
})
|
|
4038
3685
|
};
|
|
4039
3686
|
}
|
|
@@ -4062,7 +3709,7 @@ function createSlackGetChannelHistoryTool(callProxy) {
|
|
|
4062
3709
|
type: "function",
|
|
4063
3710
|
function: {
|
|
4064
3711
|
name: "slack_get_channel_history",
|
|
4065
|
-
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.
|
|
3712
|
+
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.",
|
|
4066
3713
|
parameters: {
|
|
4067
3714
|
type: "object",
|
|
4068
3715
|
properties: {
|
|
@@ -4152,7 +3799,6 @@ function createSlackTools(callProxy) {
|
|
|
4152
3799
|
return {
|
|
4153
3800
|
slack_get_me: createSlackGetMeTool(callProxy),
|
|
4154
3801
|
slack_list_channels: createSlackListChannelsTool(callProxy),
|
|
4155
|
-
slack_list_dms: createSlackListDmsTool(callProxy),
|
|
4156
3802
|
slack_search_messages: createSlackSearchMessagesTool(callProxy),
|
|
4157
3803
|
slack_list_users: createSlackListUsersTool(callProxy),
|
|
4158
3804
|
slack_get_channel_history: createSlackGetChannelHistoryTool(callProxy),
|