Skip to content

Commit 87fadfb

Browse files
committed
feat(slack): add assistant thread ops, paginated history/replies, and permalink
- New tools: slack_set_status, slack_set_title, slack_set_suggested_prompts (assistant.threads.*), slack_get_channel_history + slack_get_thread_replies (paginated conversations.history/replies via directExecution), slack_get_permalink - Wire all six as Slack block operations with subBlocks, conditions, params, outputs - Add scopes: assistant:write, im:history, mpim:read, mpim:history (+ consent labels) - Add manifest capabilities: action_read_history, action_assistant - Fix invite_to_conversation no_user error code; widen DM history scope hints - Regenerate tool docs and integrations catalog
1 parent efa4f27 commit 87fadfb

19 files changed

Lines changed: 1869 additions & 6 deletions

apps/docs/content/docs/en/tools/slack.mdx

Lines changed: 364 additions & 0 deletions
Large diffs are not rendered by default.

apps/sim/blocks/blocks/slack.ts

Lines changed: 292 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
3333
{ label: 'Read Messages', id: 'read' },
3434
{ label: 'Get Message', id: 'get_message' },
3535
{ label: 'Get Thread', id: 'get_thread' },
36+
{ label: 'Get Thread Replies', id: 'get_thread_replies' },
37+
{ label: 'Get Channel History', id: 'get_channel_history' },
38+
{ label: 'Get Message Permalink', id: 'get_permalink' },
39+
{ label: 'Set Assistant Status', id: 'set_status' },
40+
{ label: 'Set Assistant Title', id: 'set_title' },
41+
{ label: 'Set Suggested Prompts', id: 'set_suggested_prompts' },
3642
{ label: 'List Channels', id: 'list_channels' },
3743
{ label: 'List Channel Members', id: 'list_members' },
3844
{ label: 'List Users', id: 'list_users' },
@@ -548,7 +554,7 @@ Do not include any explanations, markdown formatting, or other text outside the
548554
placeholder: 'Message timestamp (e.g., 1405894322.002768)',
549555
condition: {
550556
field: 'operation',
551-
value: 'get_message',
557+
value: ['get_message', 'get_permalink'],
552558
},
553559
required: true,
554560
wandConfig: {
@@ -574,7 +580,13 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
574580
placeholder: 'Thread timestamp (thread_ts, e.g., 1405894322.002768)',
575581
condition: {
576582
field: 'operation',
577-
value: 'get_thread',
583+
value: [
584+
'get_thread',
585+
'get_thread_replies',
586+
'set_status',
587+
'set_title',
588+
'set_suggested_prompts',
589+
],
578590
},
579591
required: true,
580592
wandConfig: {
@@ -602,6 +614,150 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
602614
value: 'get_thread',
603615
},
604616
},
617+
// Set Assistant Status specific fields
618+
{
619+
id: 'status',
620+
title: 'Status Text',
621+
type: 'short-input',
622+
placeholder: 'e.g., Working on it… (leave empty to clear)',
623+
condition: {
624+
field: 'operation',
625+
value: 'set_status',
626+
},
627+
required: false,
628+
},
629+
{
630+
id: 'loadingMessages',
631+
title: 'Loading Messages',
632+
type: 'long-input',
633+
placeholder: 'Optional JSON array of phrases to animate (max 10)',
634+
condition: {
635+
field: 'operation',
636+
value: 'set_status',
637+
},
638+
required: false,
639+
},
640+
// Set Assistant Title specific fields
641+
{
642+
id: 'assistantTitle',
643+
title: 'Thread Title',
644+
type: 'short-input',
645+
placeholder: 'Title to display for the assistant thread',
646+
condition: {
647+
field: 'operation',
648+
value: 'set_title',
649+
},
650+
required: true,
651+
},
652+
// Set Suggested Prompts specific fields
653+
{
654+
id: 'suggestedPrompts',
655+
title: 'Suggested Prompts',
656+
type: 'long-input',
657+
placeholder: '[{"title": "Summarize", "message": "Summarize this thread"}]',
658+
condition: {
659+
field: 'operation',
660+
value: 'set_suggested_prompts',
661+
},
662+
required: true,
663+
wandConfig: {
664+
enabled: true,
665+
prompt: `Generate a JSON array of Slack assistant suggested prompts from the user's description.
666+
Each entry must be an object with exactly two string fields:
667+
- "title": the short label shown on the clickable chip
668+
- "message": the full message sent into the thread when the chip is clicked
669+
Return at most 4 prompts.
670+
Example:
671+
[{"title": "Summarize", "message": "Summarize the key points of this thread"}, {"title": "Next steps", "message": "What are the next steps?"}]
672+
673+
Return ONLY the JSON array - no explanations, no quotes around the array, no extra text.`,
674+
placeholder: 'Describe the prompts you want (e.g., "summarize and list action items")...',
675+
generationType: 'json-object',
676+
},
677+
},
678+
{
679+
id: 'promptsTitle',
680+
title: 'Prompts Heading',
681+
type: 'short-input',
682+
placeholder: 'e.g., Suggested Prompts (optional)',
683+
condition: {
684+
field: 'operation',
685+
value: 'set_suggested_prompts',
686+
},
687+
mode: 'advanced',
688+
required: false,
689+
},
690+
// Get Channel History / Get Thread Replies shared pagination fields
691+
{
692+
id: 'historyOldest',
693+
title: 'Oldest Timestamp',
694+
type: 'short-input',
695+
placeholder: 'Unix seconds, e.g., 1700000000 (only messages after)',
696+
condition: {
697+
field: 'operation',
698+
value: ['get_channel_history', 'get_thread_replies'],
699+
},
700+
required: false,
701+
},
702+
{
703+
id: 'historyLatest',
704+
title: 'Latest Timestamp',
705+
type: 'short-input',
706+
placeholder: 'Unix seconds, e.g., 1700000000 (only messages before)',
707+
condition: {
708+
field: 'operation',
709+
value: ['get_channel_history', 'get_thread_replies'],
710+
},
711+
required: false,
712+
},
713+
{
714+
id: 'historyLimit',
715+
title: 'Page Size',
716+
type: 'short-input',
717+
placeholder: '200 (max 999)',
718+
condition: {
719+
field: 'operation',
720+
value: ['get_channel_history', 'get_thread_replies'],
721+
},
722+
required: false,
723+
},
724+
{
725+
id: 'historyMaxPages',
726+
title: 'Max Pages',
727+
type: 'short-input',
728+
placeholder: '10',
729+
condition: {
730+
field: 'operation',
731+
value: ['get_channel_history', 'get_thread_replies'],
732+
},
733+
required: false,
734+
},
735+
{
736+
id: 'historyCursor',
737+
title: 'Start Cursor',
738+
type: 'short-input',
739+
placeholder: 'Resume from a previous nextCursor',
740+
condition: {
741+
field: 'operation',
742+
value: ['get_channel_history', 'get_thread_replies'],
743+
},
744+
required: false,
745+
},
746+
{
747+
id: 'historyInclusive',
748+
title: 'Inclusive',
749+
type: 'dropdown',
750+
options: [
751+
{ label: 'No', id: 'false' },
752+
{ label: 'Yes', id: 'true' },
753+
],
754+
value: () => 'false',
755+
condition: {
756+
field: 'operation',
757+
value: ['get_channel_history', 'get_thread_replies'],
758+
},
759+
required: false,
760+
},
605761
{
606762
id: 'oldest',
607763
title: 'Oldest Timestamp',
@@ -1196,6 +1352,12 @@ Do not include any explanations, markdown formatting, or other text outside the
11961352
'slack_message_reader',
11971353
'slack_get_message',
11981354
'slack_get_thread',
1355+
'slack_get_thread_replies',
1356+
'slack_get_channel_history',
1357+
'slack_get_permalink',
1358+
'slack_set_status',
1359+
'slack_set_title',
1360+
'slack_set_suggested_prompts',
11991361
'slack_list_channels',
12001362
'slack_list_members',
12011363
'slack_list_users',
@@ -1235,6 +1397,18 @@ Do not include any explanations, markdown formatting, or other text outside the
12351397
return 'slack_get_message'
12361398
case 'get_thread':
12371399
return 'slack_get_thread'
1400+
case 'get_thread_replies':
1401+
return 'slack_get_thread_replies'
1402+
case 'get_channel_history':
1403+
return 'slack_get_channel_history'
1404+
case 'get_permalink':
1405+
return 'slack_get_permalink'
1406+
case 'set_status':
1407+
return 'slack_set_status'
1408+
case 'set_title':
1409+
return 'slack_set_title'
1410+
case 'set_suggested_prompts':
1411+
return 'slack_set_suggested_prompts'
12381412
case 'list_channels':
12391413
return 'slack_list_channels'
12401414
case 'list_members':
@@ -1318,6 +1492,17 @@ Do not include any explanations, markdown formatting, or other text outside the
13181492
getMessageTimestamp,
13191493
getThreadTimestamp,
13201494
threadLimit,
1495+
status,
1496+
loadingMessages,
1497+
assistantTitle,
1498+
suggestedPrompts,
1499+
promptsTitle,
1500+
historyOldest,
1501+
historyLatest,
1502+
historyLimit,
1503+
historyMaxPages,
1504+
historyCursor,
1505+
historyInclusive,
13211506
includeNumMembers,
13221507
presenceUserId,
13231508
editCanvasId,
@@ -1438,6 +1623,65 @@ Do not include any explanations, markdown formatting, or other text outside the
14381623
break
14391624
}
14401625

1626+
case 'set_status': {
1627+
baseParams.threadTs = getThreadTimestamp
1628+
baseParams.status = status ?? ''
1629+
if (loadingMessages) {
1630+
baseParams.loadingMessages = loadingMessages
1631+
}
1632+
break
1633+
}
1634+
1635+
case 'set_title': {
1636+
baseParams.threadTs = getThreadTimestamp
1637+
baseParams.title = assistantTitle
1638+
break
1639+
}
1640+
1641+
case 'set_suggested_prompts': {
1642+
baseParams.threadTs = getThreadTimestamp
1643+
baseParams.prompts = suggestedPrompts
1644+
if (promptsTitle) {
1645+
baseParams.promptsTitle = promptsTitle
1646+
}
1647+
break
1648+
}
1649+
1650+
case 'get_permalink': {
1651+
baseParams.messageTs = getMessageTimestamp
1652+
break
1653+
}
1654+
1655+
case 'get_channel_history':
1656+
case 'get_thread_replies': {
1657+
if (operation === 'get_thread_replies') {
1658+
baseParams.threadTs = getThreadTimestamp
1659+
}
1660+
if (historyOldest) {
1661+
baseParams.oldest = String(historyOldest).trim()
1662+
}
1663+
if (historyLatest) {
1664+
baseParams.latest = String(historyLatest).trim()
1665+
}
1666+
if (historyLimit) {
1667+
const parsedLimit = Number.parseInt(historyLimit, 10)
1668+
if (!Number.isNaN(parsedLimit) && parsedLimit > 0) {
1669+
baseParams.limit = parsedLimit
1670+
}
1671+
}
1672+
if (historyMaxPages) {
1673+
const parsedMaxPages = Number.parseInt(historyMaxPages, 10)
1674+
if (!Number.isNaN(parsedMaxPages) && parsedMaxPages > 0) {
1675+
baseParams.maxPages = parsedMaxPages
1676+
}
1677+
}
1678+
if (historyCursor) {
1679+
baseParams.cursor = String(historyCursor).trim()
1680+
}
1681+
baseParams.inclusive = historyInclusive === 'true'
1682+
break
1683+
}
1684+
14411685
case 'list_channels': {
14421686
baseParams.includePrivate = includePrivate !== 'false'
14431687
baseParams.excludeArchived = true
@@ -1682,6 +1926,36 @@ Do not include any explanations, markdown formatting, or other text outside the
16821926
type: 'string',
16831927
description: 'Maximum number of messages to return from thread',
16841928
},
1929+
// Set Assistant Status inputs
1930+
status: { type: 'string', description: 'Status text to display (empty clears the status)' },
1931+
loadingMessages: {
1932+
type: 'json',
1933+
description: 'Optional array of phrases to animate as a loading indicator (max 10)',
1934+
},
1935+
// Set Assistant Title inputs
1936+
assistantTitle: { type: 'string', description: 'Title to display for the assistant thread' },
1937+
// Set Suggested Prompts inputs
1938+
suggestedPrompts: {
1939+
type: 'json',
1940+
description: 'Array of { title, message } prompt objects (max 4)',
1941+
},
1942+
promptsTitle: { type: 'string', description: 'Optional heading for the prompt list' },
1943+
// Get Channel History / Get Thread Replies inputs
1944+
historyOldest: {
1945+
type: 'string',
1946+
description: 'Only include messages after this Unix timestamp',
1947+
},
1948+
historyLatest: {
1949+
type: 'string',
1950+
description: 'Only include messages before this Unix timestamp',
1951+
},
1952+
historyLimit: { type: 'string', description: 'Messages to request per page (max 999)' },
1953+
historyMaxPages: { type: 'string', description: 'Maximum number of pages to fetch' },
1954+
historyCursor: { type: 'string', description: 'Pagination cursor to resume from' },
1955+
historyInclusive: {
1956+
type: 'string',
1957+
description: 'Include messages matching oldest/latest (true/false)',
1958+
},
16851959
// Get Channel Info inputs
16861960
includeNumMembers: { type: 'string', description: 'Include member count (true/false)' },
16871961
// Get User Presence inputs
@@ -1808,6 +2082,22 @@ Do not include any explanations, markdown formatting, or other text outside the
18082082
description: 'Whether there are more messages in the thread',
18092083
},
18102084

2085+
// slack_get_channel_history / slack_get_thread_replies pagination outputs
2086+
pages: {
2087+
type: 'number',
2088+
description: 'Number of pages fetched during a paginated history/replies read',
2089+
},
2090+
threadTs: {
2091+
type: 'string',
2092+
description: 'Thread timestamp an assistant status/title/prompts op was set on',
2093+
},
2094+
2095+
// slack_get_permalink outputs (get_permalink operation)
2096+
permalink: {
2097+
type: 'string',
2098+
description: 'Permalink URL to the message',
2099+
},
2100+
18112101
// slack_list_channels outputs (list_channels operation)
18122102
channels: {
18132103
type: 'json',

0 commit comments

Comments
 (0)