@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.
@@ -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 isRateLimited(status, body) {
3423
- return status === 429 || body?.ok === false && body.error === "ratelimited";
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, 1e3, 1, 5e3);
3538
- const res = await listAllConversations(callProxy, "public_channel,private_channel");
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.slice(0, limit).map((c) => ({
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
- var MAX_GROUP_DM_NAMES = 5;
3709
- var MPDM_NAME_RE = /^mpdm-(.+)-\d+$/;
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 getAuthUserId = makeGetAuthUserId(callProxy);
3791
- const getUsersDirectory = makeGetUsersDirectory(callProxy);
3792
- let fromId = null;
3793
- if (fromUserRef) {
3794
- fromId = await resolveSlackUserId(fromUserRef, getAuthUserId, getUsersDirectory);
3795
- if (!fromId)
3796
- return `Error: couldn't find a Slack user matching "${fromUserRef}" for from_user.`;
3797
- }
3798
- let mentionId = null;
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 raw = args.channel.trim();
3818
- const bare = raw.replace(/^#/, "");
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 (isRateLimited(status, body)) {
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(passes);
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.push({
3860
- text: humanizeSlackText(m.text ?? "", directory),
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
- sliced.push({ note: SLACK_PENDING_APPROVAL_NOTE });
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 sliced;
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 resolved = await resolveChannelId(callProxy, args.channel);
3889
- if (typeof resolved === "string") return resolved;
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
- status,
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: humanizeSlackText(m.text ?? "", directory),
3905
- user: authorName(m, directory),
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 { status, json } = await callProxy("/conversations.replies", {
3912
- channel: args.channel,
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
- status,
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: humanizeSlackText(m.text ?? "", directory),
3927
- user: authorName(m, directory),
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 5000 (clamped). Defaults to 1000."
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. Filter by any combination of 'query' (words the text must contain), 'from_user' (the author), and 'mentions' (who the message @-mentions) -- at least one is required. Only recent history is scanned (a bounded set of conversations), so this surfaces recent messages rather than the full archive. Use this to find messages by KEYWORD or TOPIC across conversations. Do NOT use it to read the latest/last message from a specific person or channel, or to read a specific conversation you already know: for the last message from a person, call slack_list_dms with with_user to get the DM id then slack_get_channel_history on it; for a channel, call slack_get_channel_history directly. Search fans out across many conversations and is heavily rate-limited, so a single targeted read is faster and more reliable.",
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: "Optional. Words to look for; a message matches when its text contains all of them (case-insensitive). Provide this, from_user, or mentions."
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. This is the right tool to read the most recent messages (including just the latest one with limit: 1) from a known channel or DM id, and should be PREFERRED over slack_search_messages whenever the conversation to read is already known or identified.",
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),