From 0fafe3e264d506cde88ea611c46758392ac730ab Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Mon, 31 Aug 2026 20:06:02 -0700 Subject: [PATCH 1/2] fix(slack): restore assistant operation compatibility --- apps/docs/content/docs/integrations/slack.mdx | 45 ++++++++ apps/sim/blocks/blocks/slack.test.ts | 61 +++++++++-- apps/sim/blocks/blocks/slack.ts | 100 ++++++++++++++---- .../deployment-config/src/integrations.json | 10 +- 4 files changed, 182 insertions(+), 34 deletions(-) diff --git a/apps/docs/content/docs/integrations/slack.mdx b/apps/docs/content/docs/integrations/slack.mdx index 3bb636602ae..d237bca88fd 100644 --- a/apps/docs/content/docs/integrations/slack.mdx +++ b/apps/docs/content/docs/integrations/slack.mdx @@ -816,6 +816,51 @@ Get a stable permalink URL to a specific Slack message. | `channel` | string | Channel ID containing the message | | `permalink` | string | The permalink URL to the message | +### Slack Set Assistant Status + +Set or clear the assistant thread status indicator (the loading shimmer) on a Slack AI app thread. Pass an empty status to clear it. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `authMethod` | string | No | Authentication method: oauth or bot_token | +| `botToken` | string | No | Bot token for Custom Bot | +| `channel` | string | Yes | Channel ID containing the assistant thread \(e.g., C1234567890 or D1234567890\) | +| `threadTs` | string | Yes | Thread timestamp \(thread_ts\) of the assistant thread \(e.g., 1405894322.002768\) | +| `status` | string | No | Status text to display, e.g. 'Working on it…'. Omit or pass an empty string to clear the status. | +| `loadingMessages` | json | No | Optional list of messages to rotate through as an animated loading indicator \(max 10\). | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `ok` | boolean | Whether the status was set successfully | +| `channel` | string | Channel ID the status was set on | +| `threadTs` | string | Thread timestamp the status was set on | + +### Slack Set Assistant Title + +Set the title of a Slack assistant thread (shown in the AI app thread header). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `authMethod` | string | No | Authentication method: oauth or bot_token | +| `botToken` | string | No | Bot token for Custom Bot | +| `channel` | string | Yes | Channel ID containing the assistant thread \(e.g., C1234567890 or D1234567890\) | +| `threadTs` | string | Yes | Thread timestamp \(thread_ts\) of the assistant thread \(e.g., 1405894322.002768\) | +| `title` | string | Yes | The title to display for the assistant thread | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `ok` | boolean | Whether the title was set successfully | +| `channel` | string | Channel ID the title was set on | +| `threadTs` | string | Thread timestamp the title was set on | + ### Slack Set Suggested Prompts Set the clickable suggested prompts shown in a Slack assistant thread (the prompt chips in an AI app). diff --git a/apps/sim/blocks/blocks/slack.test.ts b/apps/sim/blocks/blocks/slack.test.ts index 78fe4d124c0..e0f08cfc156 100644 --- a/apps/sim/blocks/blocks/slack.test.ts +++ b/apps/sim/blocks/blocks/slack.test.ts @@ -2,6 +2,7 @@ * @vitest-environment node */ import { describe, expect, it } from 'vitest' +import { evaluateSubBlockCondition } from '@/lib/workflows/subblocks/visibility' import { getSlackV2ActionSubBlocks, getSlackV2OperationSentences, @@ -20,6 +21,8 @@ const AGENT_TOOL_IDS = [ 'slack_set_agent_session_status_v2', 'slack_rename_agent_session_v2', ] +const LEGACY_OPERATION_IDS = ['set_status', 'set_title'] +const LEGACY_TOOL_IDS = ['slack_set_status', 'slack_set_title'] function operationIds(): string[] { const operation = SlackV2Block.subBlocks.find((subBlock) => subBlock.id === 'operation') @@ -32,6 +35,12 @@ function mapSlackV2Params(params: Record): Record): boolean { + const subBlock = SlackV2Block.subBlocks.find((candidate) => candidate.id === subBlockId) + if (!subBlock) throw new Error(`Slack v2 subblock not found: ${subBlockId}`) + return evaluateSubBlockCondition(subBlock.condition, values) +} + describe('Slack block release', () => { it('releases slack_v2 and keeps the legacy block executable but hidden', () => { expect(SlackBlock.hideFromToolbar).toBe(true) @@ -41,21 +50,27 @@ describe('Slack block release', () => { expect(SlackV2Block.sunset).toBeUndefined() }) - it('replaces legacy assistant operations with custom-bot Agent Sessions operations', () => { - expect(operationIds()).toEqual(expect.arrayContaining(AGENT_OPERATION_IDS)) - for (const id of ['set_status', 'set_title']) { - expect(operationIds()).not.toContain(id) - } - expect(getSlackV2ToolAccess()).toEqual(expect.arrayContaining(AGENT_TOOL_IDS)) + it('adds custom-bot Agent Sessions operations without removing legacy assistant operations', () => { + expect(operationIds()).toEqual( + expect.arrayContaining([...LEGACY_OPERATION_IDS, ...AGENT_OPERATION_IDS]) + ) + expect(getSlackV2ToolAccess()).toEqual( + expect.arrayContaining([...LEGACY_TOOL_IDS, ...AGENT_TOOL_IDS]) + ) expect(getSlackV2ToolAccess()).toContain('slack_set_suggested_prompts') - for (const id of ['slack_set_status', 'slack_set_title']) { - expect(getSlackV2ToolAccess()).not.toContain(id) - } expect(Object.keys(getSlackV2OperationSentences())).toEqual( - expect.arrayContaining(AGENT_OPERATION_IDS) + expect.arrayContaining([...LEGACY_OPERATION_IDS, ...AGENT_OPERATION_IDS]) ) }) + it('keeps legacy assistant operations routed to their original tools', () => { + const selectTool = SlackV2Block.tools.config?.tool + if (!selectTool) throw new Error('Slack v2 tool selector is required') + + expect(selectTool({ operation: 'set_status' })).toBe('slack_set_status') + expect(selectTool({ operation: 'set_title' })).toBe('slack_set_title') + }) + it('uses a service-account-only picker for Agent Sessions operations', () => { const credential = getSlackV2ActionSubBlocks().find( (subBlock) => subBlock.id === 'agentBotCredential' @@ -90,6 +105,19 @@ describe('Slack block release', () => { prompts: '[{"title":"Summarize","message":"Summarize this thread"}]', promptsTitle: 'Try asking', }) + + const legacyValues = { + operation: 'set_suggested_prompts', + credential: 'oauth-credential', + channel: 'C123', + getThreadTimestamp: '1700000000.000001', + } + expect(isSlackV2SubBlockVisible('credential', legacyValues)).toBe(true) + expect(isSlackV2SubBlockVisible('channel', legacyValues)).toBe(true) + expect(isSlackV2SubBlockVisible('getThreadTimestamp', legacyValues)).toBe(true) + expect(isSlackV2SubBlockVisible('agentBotCredential', legacyValues)).toBe(false) + expect(isSlackV2SubBlockVisible('agentChannel', legacyValues)).toBe(false) + expect(isSlackV2SubBlockVisible('agentThreadTs', legacyValues)).toBe(false) }) it('uses service-account tools for new agent operations', () => { @@ -116,5 +144,18 @@ describe('Slack block release', () => { threadTs: '1700000000.000001', status: 'processing', }) + + const agentPromptValues = { + operation: 'set_suggested_prompts', + agentBotCredential: 'custom-bot', + agentChannel: 'D123', + agentThreadTs: '1700000000.000001', + } + expect(isSlackV2SubBlockVisible('credential', agentPromptValues)).toBe(false) + expect(isSlackV2SubBlockVisible('channel', agentPromptValues)).toBe(false) + expect(isSlackV2SubBlockVisible('getThreadTimestamp', agentPromptValues)).toBe(false) + expect(isSlackV2SubBlockVisible('agentBotCredential', agentPromptValues)).toBe(true) + expect(isSlackV2SubBlockVisible('agentChannel', agentPromptValues)).toBe(true) + expect(isSlackV2SubBlockVisible('agentThreadTs', agentPromptValues)).toBe(true) }) }) diff --git a/apps/sim/blocks/blocks/slack.ts b/apps/sim/blocks/blocks/slack.ts index 5de1cff9c7c..c5932cf0aec 100644 --- a/apps/sim/blocks/blocks/slack.ts +++ b/apps/sim/blocks/blocks/slack.ts @@ -21,6 +21,49 @@ const SLACK_V2_AGENT_OPERATIONS = [ 'rename_agent_session', ] as const +const SLACK_V2_SESSION_OPERATIONS = ['set_agent_session_status', 'rename_agent_session'] as const + +function hasConfiguredSlackValue( + values: Record | undefined, + fieldIds: readonly string[] +): boolean { + return fieldIds.some((fieldId) => { + const value = values?.[fieldId] + return value !== undefined && value !== null && value !== '' + }) +} + +function isLegacySuggestedPromptsConfiguration(values?: Record): boolean { + if (values?.operation !== 'set_suggested_prompts') return false + + const hasAgentFields = hasConfiguredSlackValue(values, [ + 'agentBotCredential', + 'manualAgentBotCredential', + 'agentChannel', + 'manualAgentChannel', + 'agentThreadTs', + ]) + if (hasAgentFields) return false + + return hasConfiguredSlackValue(values, [ + 'credential', + 'manualCredential', + 'channel', + 'manualChannel', + 'getThreadTimestamp', + ]) +} + +function getSlackV2AgentOperationCondition(values?: Record) { + return { + field: 'operation' as const, + value: [ + ...(isLegacySuggestedPromptsConfiguration(values) ? [] : ['set_suggested_prompts']), + ...SLACK_V2_SESSION_OPERATIONS, + ], + } +} + const CHANNEL_FIELD = ['channel', 'manualChannel'] as const /** @@ -2948,14 +2991,20 @@ function adaptSubBlockForV2(sb: SubBlockConfig): SubBlockConfig { serviceAccountGroup: 'Custom bots', serviceAccountConnect: 'Set up a custom bot', }, - condition: { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS], not: true }, + condition: (values?: Record) => + isLegacySuggestedPromptsConfiguration(values) + ? { field: 'operation', value: 'set_suggested_prompts' } + : { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS], not: true }, } } if (sb.id === 'manualCredential') { return { ...rest, placeholder: 'Enter credential ID', - condition: { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS], not: true }, + condition: (values?: Record) => + isLegacySuggestedPromptsConfiguration(values) + ? { field: 'operation', value: 'set_suggested_prompts' } + : { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS], not: true }, } } if (sb.id === 'channel' || sb.id === 'manualChannel') { @@ -2963,7 +3012,10 @@ function adaptSubBlockForV2(sb: SubBlockConfig): SubBlockConfig { ...sb, dependsOn: ['credential'], condition: (values?: Record) => { - if (SLACK_V2_AGENT_OPERATIONS.includes(values?.operation as never)) { + if ( + SLACK_V2_AGENT_OPERATIONS.includes(values?.operation as never) && + !isLegacySuggestedPromptsConfiguration(values) + ) { return { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS], not: true } } if (typeof condition !== 'function') { @@ -2973,7 +3025,7 @@ function adaptSubBlockForV2(sb: SubBlockConfig): SubBlockConfig { }, required: { field: 'operation', - value: ['list_canvases', 'list_scheduled_messages', ...SLACK_V2_AGENT_OPERATIONS], + value: ['list_canvases', 'list_scheduled_messages', ...SLACK_V2_SESSION_OPERATIONS], not: true, }, } @@ -2981,7 +3033,16 @@ function adaptSubBlockForV2(sb: SubBlockConfig): SubBlockConfig { if (sb.id === 'getThreadTimestamp') { return { ...sb, - condition: { field: 'operation', value: ['get_thread', 'get_thread_replies'] }, + condition: (values?: Record) => ({ + field: 'operation', + value: [ + 'get_thread', + 'get_thread_replies', + 'set_status', + 'set_title', + ...(isLegacySuggestedPromptsConfiguration(values) ? ['set_suggested_prompts'] : []), + ], + }), required: true, } } @@ -3006,7 +3067,7 @@ function getSlackV2AgentSubBlocks(): SubBlockConfig[] { serviceAccountGroup: 'Custom bots', serviceAccountConnect: 'Set up a custom bot', }, - condition: { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS] }, + condition: getSlackV2AgentOperationCondition, required: true, mode: 'basic', }, @@ -3016,7 +3077,7 @@ function getSlackV2AgentSubBlocks(): SubBlockConfig[] { type: 'short-input', canonicalParamId: 'agentCredentialId', placeholder: 'Enter custom bot credential ID', - condition: { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS] }, + condition: getSlackV2AgentOperationCondition, required: true, mode: 'advanced', }, @@ -3029,7 +3090,7 @@ function getSlackV2AgentSubBlocks(): SubBlockConfig[] { selectorKey: 'slack.channels', placeholder: 'Select Slack channel', dependsOn: ['agentBotCredential'], - condition: { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS] }, + condition: getSlackV2AgentOperationCondition, required: true, mode: 'basic', }, @@ -3039,7 +3100,7 @@ function getSlackV2AgentSubBlocks(): SubBlockConfig[] { type: 'short-input', canonicalParamId: 'agentChannelId', placeholder: 'Enter Slack channel ID', - condition: { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS] }, + condition: getSlackV2AgentOperationCondition, required: true, mode: 'advanced', }, @@ -3048,10 +3109,7 @@ function getSlackV2AgentSubBlocks(): SubBlockConfig[] { title: 'Thread Timestamp', type: 'short-input', placeholder: 'Thread timestamp (thread_ts)', - condition: { - field: 'operation', - value: ['set_suggested_prompts', 'set_agent_session_status', 'rename_agent_session'], - }, + condition: getSlackV2AgentOperationCondition, required: { field: 'operation', value: ['set_agent_session_status', 'rename_agent_session'], @@ -3153,17 +3211,9 @@ export function getSlackV2OperationSentences() { if (!operationSentences) { throw new Error('Slack action sentences must be defined before building slack_v2') } - const { set_status: _setStatus, set_title: _setTitle, ...v2Sentences } = operationSentences return { - ...v2Sentences, - set_suggested_prompts: [ - { - text: 'Set suggested prompts in', - field: ['agentChannel', 'manualAgentChannel'], - core: true, - }, - { text: ', for thread', field: 'agentThreadTs' }, - ], + ...operationSentences, + set_suggested_prompts: ['Set suggested prompts'], set_agent_session_status: [ { text: 'Set agent session to', field: 'agentSessionStatus', core: true }, { text: 'on thread', field: 'agentThreadTs', core: true }, @@ -3239,6 +3289,8 @@ export const SlackV2Block: BlockConfig = { { label: 'Get Thread Replies', id: 'get_thread_replies' }, { label: 'Get Channel History', id: 'get_channel_history' }, { label: 'Get Message Permalink', id: 'get_permalink' }, + { label: 'Set Assistant Status', id: 'set_status' }, + { label: 'Set Assistant Title', id: 'set_title' }, { label: 'Set Suggested Prompts', id: 'set_suggested_prompts' }, { label: 'Set Agent Session Status', id: 'set_agent_session_status' }, { label: 'Rename Agent Session', id: 'rename_agent_session' }, @@ -3290,6 +3342,8 @@ export const SlackV2Block: BlockConfig = { 'slack_get_thread_replies', 'slack_get_channel_history', 'slack_get_permalink', + 'slack_set_status', + 'slack_set_title', 'slack_set_suggested_prompts', 'slack_set_suggested_prompts_v2', 'slack_set_agent_session_status_v2', diff --git a/packages/deployment-config/src/integrations.json b/packages/deployment-config/src/integrations.json index 8913631a032..c8a1b54abf3 100644 --- a/packages/deployment-config/src/integrations.json +++ b/packages/deployment-config/src/integrations.json @@ -21272,6 +21272,14 @@ "name": "Get Message Permalink", "description": "Get a stable permalink URL to a specific Slack message." }, + { + "name": "Set Assistant Status", + "description": "Set or clear the assistant thread status indicator (the loading shimmer) on a Slack AI app thread. Pass an empty status to clear it." + }, + { + "name": "Set Assistant Title", + "description": "Set the title of a Slack assistant thread (shown in the AI app thread header)." + }, { "name": "Set Suggested Prompts", "description": "Set the clickable suggested prompts shown in a Slack assistant thread (the prompt chips in an AI app)." @@ -21405,7 +21413,7 @@ "description": "Set the purpose (description) for a Slack channel (max 250 characters)." } ], - "operationCount": 42, + "operationCount": 44, "triggers": [ { "id": "slack_oauth", From dedc666b3902a695977bf24d87ec0af02bd4891d Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Mon, 31 Aug 2026 20:45:06 -0700 Subject: [PATCH 2/2] fix(slack): split assistant and agent prompts --- apps/sim/blocks/blocks/slack.test.ts | 67 ++++++++--- apps/sim/blocks/blocks/slack.ts | 106 ++++++------------ .../deployment-config/src/integrations.json | 8 +- 3 files changed, 90 insertions(+), 91 deletions(-) diff --git a/apps/sim/blocks/blocks/slack.test.ts b/apps/sim/blocks/blocks/slack.test.ts index e0f08cfc156..8cb48edd031 100644 --- a/apps/sim/blocks/blocks/slack.test.ts +++ b/apps/sim/blocks/blocks/slack.test.ts @@ -12,7 +12,7 @@ import { } from '@/blocks/blocks/slack' const AGENT_OPERATION_IDS = [ - 'set_suggested_prompts', + 'set_agent_suggested_prompts', 'set_agent_session_status', 'rename_agent_session', ] @@ -21,8 +21,8 @@ const AGENT_TOOL_IDS = [ 'slack_set_agent_session_status_v2', 'slack_rename_agent_session_v2', ] -const LEGACY_OPERATION_IDS = ['set_status', 'set_title'] -const LEGACY_TOOL_IDS = ['slack_set_status', 'slack_set_title'] +const ASSISTANT_OPERATION_IDS = ['set_status', 'set_title', 'set_suggested_prompts'] +const ASSISTANT_TOOL_IDS = ['slack_set_status', 'slack_set_title'] function operationIds(): string[] { const operation = SlackV2Block.subBlocks.find((subBlock) => subBlock.id === 'operation') @@ -50,20 +50,20 @@ describe('Slack block release', () => { expect(SlackV2Block.sunset).toBeUndefined() }) - it('adds custom-bot Agent Sessions operations without removing legacy assistant operations', () => { + it('adds custom-bot Agent Sessions operations without removing assistant operations', () => { expect(operationIds()).toEqual( - expect.arrayContaining([...LEGACY_OPERATION_IDS, ...AGENT_OPERATION_IDS]) + expect.arrayContaining([...ASSISTANT_OPERATION_IDS, ...AGENT_OPERATION_IDS]) ) expect(getSlackV2ToolAccess()).toEqual( - expect.arrayContaining([...LEGACY_TOOL_IDS, ...AGENT_TOOL_IDS]) + expect.arrayContaining([...ASSISTANT_TOOL_IDS, ...AGENT_TOOL_IDS]) ) expect(getSlackV2ToolAccess()).toContain('slack_set_suggested_prompts') expect(Object.keys(getSlackV2OperationSentences())).toEqual( - expect.arrayContaining([...LEGACY_OPERATION_IDS, ...AGENT_OPERATION_IDS]) + expect.arrayContaining([...ASSISTANT_OPERATION_IDS, ...AGENT_OPERATION_IDS]) ) }) - it('keeps legacy assistant operations routed to their original tools', () => { + it('keeps assistant operations routed to their original tools', () => { const selectTool = SlackV2Block.tools.config?.tool if (!selectTool) throw new Error('Slack v2 tool selector is required') @@ -82,7 +82,7 @@ describe('Slack block release', () => { }) }) - it('keeps persisted OAuth suggested prompts on the compatibility tool', () => { + it('keeps assistant suggested prompts on the original fields and tool', () => { const selectTool = SlackV2Block.tools.config?.tool if (!selectTool) throw new Error('Slack v2 tool selector is required') @@ -106,18 +106,19 @@ describe('Slack block release', () => { promptsTitle: 'Try asking', }) - const legacyValues = { + const assistantValues = { operation: 'set_suggested_prompts', credential: 'oauth-credential', channel: 'C123', getThreadTimestamp: '1700000000.000001', } - expect(isSlackV2SubBlockVisible('credential', legacyValues)).toBe(true) - expect(isSlackV2SubBlockVisible('channel', legacyValues)).toBe(true) - expect(isSlackV2SubBlockVisible('getThreadTimestamp', legacyValues)).toBe(true) - expect(isSlackV2SubBlockVisible('agentBotCredential', legacyValues)).toBe(false) - expect(isSlackV2SubBlockVisible('agentChannel', legacyValues)).toBe(false) - expect(isSlackV2SubBlockVisible('agentThreadTs', legacyValues)).toBe(false) + expect(isSlackV2SubBlockVisible('credential', assistantValues)).toBe(true) + expect(isSlackV2SubBlockVisible('channel', assistantValues)).toBe(true) + expect(isSlackV2SubBlockVisible('getThreadTimestamp', assistantValues)).toBe(true) + expect(isSlackV2SubBlockVisible('suggestedPrompts', assistantValues)).toBe(true) + expect(isSlackV2SubBlockVisible('agentBotCredential', assistantValues)).toBe(false) + expect(isSlackV2SubBlockVisible('agentChannel', assistantValues)).toBe(false) + expect(isSlackV2SubBlockVisible('agentThreadTs', assistantValues)).toBe(false) }) it('uses service-account tools for new agent operations', () => { @@ -125,7 +126,7 @@ describe('Slack block release', () => { if (!selectTool) throw new Error('Slack v2 tool selector is required') expect( - selectTool({ operation: 'set_suggested_prompts', agentCredentialId: 'custom-bot' }) + selectTool({ operation: 'set_agent_suggested_prompts', agentCredentialId: 'custom-bot' }) ).toBe('slack_set_suggested_prompts_v2') expect(selectTool({ operation: 'set_agent_session_status' })).toBe( 'slack_set_agent_session_status_v2' @@ -146,7 +147,7 @@ describe('Slack block release', () => { }) const agentPromptValues = { - operation: 'set_suggested_prompts', + operation: 'set_agent_suggested_prompts', agentBotCredential: 'custom-bot', agentChannel: 'D123', agentThreadTs: '1700000000.000001', @@ -154,8 +155,38 @@ describe('Slack block release', () => { expect(isSlackV2SubBlockVisible('credential', agentPromptValues)).toBe(false) expect(isSlackV2SubBlockVisible('channel', agentPromptValues)).toBe(false) expect(isSlackV2SubBlockVisible('getThreadTimestamp', agentPromptValues)).toBe(false) + expect(isSlackV2SubBlockVisible('suggestedPrompts', agentPromptValues)).toBe(true) expect(isSlackV2SubBlockVisible('agentBotCredential', agentPromptValues)).toBe(true) expect(isSlackV2SubBlockVisible('agentChannel', agentPromptValues)).toBe(true) expect(isSlackV2SubBlockVisible('agentThreadTs', agentPromptValues)).toBe(true) + + expect( + mapSlackV2Params({ + operation: 'set_agent_suggested_prompts', + agentCredentialId: 'custom-bot', + agentChannelId: 'D123', + agentThreadTs: '1700000000.000001', + suggestedPrompts: '[{"title":"Summarize","message":"Summarize this thread"}]', + promptsTitle: 'Try asking', + }) + ).toMatchObject({ + credential: 'custom-bot', + channel: 'D123', + threadTs: '1700000000.000001', + prompts: '[{"title":"Summarize","message":"Summarize this thread"}]', + promptsTitle: 'Try asking', + }) + + const repurposedValues = { + operation: 'set_agent_suggested_prompts', + credential: 'stale-credential', + channel: 'C123', + suggestedPrompts: '[{"title":"Summarize","message":"Summarize this thread"}]', + } + expect(isSlackV2SubBlockVisible('credential', repurposedValues)).toBe(false) + expect(isSlackV2SubBlockVisible('channel', repurposedValues)).toBe(false) + expect(isSlackV2SubBlockVisible('agentBotCredential', repurposedValues)).toBe(true) + expect(isSlackV2SubBlockVisible('agentChannel', repurposedValues)).toBe(true) + expect(selectTool(repurposedValues)).toBe('slack_set_suggested_prompts_v2') }) }) diff --git a/apps/sim/blocks/blocks/slack.ts b/apps/sim/blocks/blocks/slack.ts index c5932cf0aec..4fe5904b7a8 100644 --- a/apps/sim/blocks/blocks/slack.ts +++ b/apps/sim/blocks/blocks/slack.ts @@ -16,54 +16,13 @@ import { getTrigger } from '@/triggers' const DESTINATION_SWITCH_OPERATIONS = ['send', 'read', 'schedule_message'] as const const SLACK_V2_AGENT_OPERATIONS = [ - 'set_suggested_prompts', + 'set_agent_suggested_prompts', 'set_agent_session_status', 'rename_agent_session', ] as const const SLACK_V2_SESSION_OPERATIONS = ['set_agent_session_status', 'rename_agent_session'] as const -function hasConfiguredSlackValue( - values: Record | undefined, - fieldIds: readonly string[] -): boolean { - return fieldIds.some((fieldId) => { - const value = values?.[fieldId] - return value !== undefined && value !== null && value !== '' - }) -} - -function isLegacySuggestedPromptsConfiguration(values?: Record): boolean { - if (values?.operation !== 'set_suggested_prompts') return false - - const hasAgentFields = hasConfiguredSlackValue(values, [ - 'agentBotCredential', - 'manualAgentBotCredential', - 'agentChannel', - 'manualAgentChannel', - 'agentThreadTs', - ]) - if (hasAgentFields) return false - - return hasConfiguredSlackValue(values, [ - 'credential', - 'manualCredential', - 'channel', - 'manualChannel', - 'getThreadTimestamp', - ]) -} - -function getSlackV2AgentOperationCondition(values?: Record) { - return { - field: 'operation' as const, - value: [ - ...(isLegacySuggestedPromptsConfiguration(values) ? [] : ['set_suggested_prompts']), - ...SLACK_V2_SESSION_OPERATIONS, - ], - } -} - const CHANNEL_FIELD = ['channel', 'manualChannel'] as const /** @@ -2991,20 +2950,14 @@ function adaptSubBlockForV2(sb: SubBlockConfig): SubBlockConfig { serviceAccountGroup: 'Custom bots', serviceAccountConnect: 'Set up a custom bot', }, - condition: (values?: Record) => - isLegacySuggestedPromptsConfiguration(values) - ? { field: 'operation', value: 'set_suggested_prompts' } - : { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS], not: true }, + condition: { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS], not: true }, } } if (sb.id === 'manualCredential') { return { ...rest, placeholder: 'Enter credential ID', - condition: (values?: Record) => - isLegacySuggestedPromptsConfiguration(values) - ? { field: 'operation', value: 'set_suggested_prompts' } - : { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS], not: true }, + condition: { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS], not: true }, } } if (sb.id === 'channel' || sb.id === 'manualChannel') { @@ -3012,10 +2965,7 @@ function adaptSubBlockForV2(sb: SubBlockConfig): SubBlockConfig { ...sb, dependsOn: ['credential'], condition: (values?: Record) => { - if ( - SLACK_V2_AGENT_OPERATIONS.includes(values?.operation as never) && - !isLegacySuggestedPromptsConfiguration(values) - ) { + if (SLACK_V2_AGENT_OPERATIONS.includes(values?.operation as never)) { return { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS], not: true } } if (typeof condition !== 'function') { @@ -3025,7 +2975,7 @@ function adaptSubBlockForV2(sb: SubBlockConfig): SubBlockConfig { }, required: { field: 'operation', - value: ['list_canvases', 'list_scheduled_messages', ...SLACK_V2_SESSION_OPERATIONS], + value: ['list_canvases', 'list_scheduled_messages', ...SLACK_V2_AGENT_OPERATIONS], not: true, }, } @@ -3033,19 +2983,28 @@ function adaptSubBlockForV2(sb: SubBlockConfig): SubBlockConfig { if (sb.id === 'getThreadTimestamp') { return { ...sb, - condition: (values?: Record) => ({ + condition: { field: 'operation', value: [ 'get_thread', 'get_thread_replies', 'set_status', 'set_title', - ...(isLegacySuggestedPromptsConfiguration(values) ? ['set_suggested_prompts'] : []), + 'set_suggested_prompts', ], - }), + }, required: true, } } + if (sb.id === 'suggestedPrompts' || sb.id === 'promptsTitle') { + return { + ...sb, + condition: { + field: 'operation', + value: ['set_suggested_prompts', 'set_agent_suggested_prompts'], + }, + } + } if (dependsOn && !Array.isArray(dependsOn) && dependsOn.all?.includes('authMethod')) { return { ...sb, dependsOn: ['credential'] } } @@ -3067,7 +3026,7 @@ function getSlackV2AgentSubBlocks(): SubBlockConfig[] { serviceAccountGroup: 'Custom bots', serviceAccountConnect: 'Set up a custom bot', }, - condition: getSlackV2AgentOperationCondition, + condition: { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS] }, required: true, mode: 'basic', }, @@ -3077,7 +3036,7 @@ function getSlackV2AgentSubBlocks(): SubBlockConfig[] { type: 'short-input', canonicalParamId: 'agentCredentialId', placeholder: 'Enter custom bot credential ID', - condition: getSlackV2AgentOperationCondition, + condition: { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS] }, required: true, mode: 'advanced', }, @@ -3090,7 +3049,7 @@ function getSlackV2AgentSubBlocks(): SubBlockConfig[] { selectorKey: 'slack.channels', placeholder: 'Select Slack channel', dependsOn: ['agentBotCredential'], - condition: getSlackV2AgentOperationCondition, + condition: { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS] }, required: true, mode: 'basic', }, @@ -3100,7 +3059,7 @@ function getSlackV2AgentSubBlocks(): SubBlockConfig[] { type: 'short-input', canonicalParamId: 'agentChannelId', placeholder: 'Enter Slack channel ID', - condition: getSlackV2AgentOperationCondition, + condition: { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS] }, required: true, mode: 'advanced', }, @@ -3109,7 +3068,7 @@ function getSlackV2AgentSubBlocks(): SubBlockConfig[] { title: 'Thread Timestamp', type: 'short-input', placeholder: 'Thread timestamp (thread_ts)', - condition: getSlackV2AgentOperationCondition, + condition: { field: 'operation', value: [...SLACK_V2_AGENT_OPERATIONS] }, required: { field: 'operation', value: ['set_agent_session_status', 'rename_agent_session'], @@ -3213,7 +3172,14 @@ export function getSlackV2OperationSentences() { } return { ...operationSentences, - set_suggested_prompts: ['Set suggested prompts'], + set_agent_suggested_prompts: [ + { + text: 'Set agent suggested prompts in', + field: ['agentChannel', 'manualAgentChannel'], + core: true, + }, + { text: ', for thread', field: 'agentThreadTs' }, + ], set_agent_session_status: [ { text: 'Set agent session to', field: 'agentSessionStatus', core: true }, { text: 'on thread', field: 'agentThreadTs', core: true }, @@ -3291,7 +3257,8 @@ export const SlackV2Block: BlockConfig = { { label: 'Get Message Permalink', id: 'get_permalink' }, { label: 'Set Assistant Status', id: 'set_status' }, { label: 'Set Assistant Title', id: 'set_title' }, - { label: 'Set Suggested Prompts', id: 'set_suggested_prompts' }, + { label: 'Set Assistant Suggested Prompts', id: 'set_suggested_prompts' }, + { label: 'Set Agent Suggested Prompts', id: 'set_agent_suggested_prompts' }, { label: 'Set Agent Session Status', id: 'set_agent_session_status' }, { label: 'Rename Agent Session', id: 'rename_agent_session' }, { label: 'List Channels', id: 'list_channels' }, @@ -3383,9 +3350,9 @@ export const SlackV2Block: BlockConfig = { tool: (params) => { switch (params.operation) { case 'set_suggested_prompts': - return params.agentCredentialId - ? 'slack_set_suggested_prompts_v2' - : 'slack_set_suggested_prompts' + return 'slack_set_suggested_prompts' + case 'set_agent_suggested_prompts': + return 'slack_set_suggested_prompts_v2' case 'set_agent_session_status': return 'slack_set_agent_session_status_v2' case 'rename_agent_session': @@ -3402,9 +3369,6 @@ export const SlackV2Block: BlockConfig = { if (!mapParams) throw new Error('Slack parameter mapper is required') const baseParams = mapParams(params) if (!SLACK_V2_AGENT_OPERATIONS.includes(params.operation as never)) return baseParams - if (params.operation === 'set_suggested_prompts' && !params.agentCredentialId) { - return baseParams - } return { ...baseParams, diff --git a/packages/deployment-config/src/integrations.json b/packages/deployment-config/src/integrations.json index c8a1b54abf3..9126e0de16e 100644 --- a/packages/deployment-config/src/integrations.json +++ b/packages/deployment-config/src/integrations.json @@ -21281,9 +21281,13 @@ "description": "Set the title of a Slack assistant thread (shown in the AI app thread header)." }, { - "name": "Set Suggested Prompts", + "name": "Set Assistant Suggested Prompts", "description": "Set the clickable suggested prompts shown in a Slack assistant thread (the prompt chips in an AI app)." }, + { + "name": "Set Agent Suggested Prompts", + "description": "Set suggested prompts in Slack Agent View, optionally scoped to a specific thread." + }, { "name": "Set Agent Session Status", "description": "Create or update the state of a Slack agent session associated with a thread." @@ -21413,7 +21417,7 @@ "description": "Set the purpose (description) for a Slack channel (max 250 characters)." } ], - "operationCount": 44, + "operationCount": 45, "triggers": [ { "id": "slack_oauth",