Skip to content

Commit 044e034

Browse files
authored
fix(integrations): gdrive trashed search, slack blocks-with-file, slack get_message ts (#4600)
* fix(integrations): gdrive trashed search, slack blocks-with-file, slack get_message ts - Google Drive search/list: skip default `trashed = false` when user query already specifies a `trashed = ...` predicate, so trashed-file searches work. - Slack send-message with files: forward `blocks` through to `files.completeUploadExternal` so Block Kit renders when files are attached. - Slack get_message: switch from `conversations.history` (oldest lower-bound returned the next message after) to `conversations.replies` with `ts=` for exact-match lookup, plus a defensive ts-equality guard and clearer error. * fix(google_drive): revert list.ts trashed guard — query is plain text, not gdrive syntax * fix(slack): omit initial_comment when blocks present so Block Kit actually renders on file uploads
1 parent 642231f commit 044e034

4 files changed

Lines changed: 45 additions & 13 deletions

File tree

apps/sim/app/api/tools/slack/utils.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ async function completeSlackFileUpload(
141141
channel: string,
142142
text: string,
143143
accessToken: string,
144-
threadTs?: string | null
144+
threadTs?: string | null,
145+
blocks?: unknown[] | null
145146
): Promise<{ ok: boolean; files?: any[]; error?: string }> {
146147
const response = await fetch('https://slack.com/api/files.completeUploadExternal', {
147148
method: 'POST',
@@ -152,7 +153,10 @@ async function completeSlackFileUpload(
152153
body: JSON.stringify({
153154
files: uploadedFileIds.map((id) => ({ id })),
154155
channel_id: channel,
155-
initial_comment: text,
156+
// Per Slack docs for files.completeUploadExternal: if `initial_comment`
157+
// is provided, `blocks` is silently ignored. So when blocks are present
158+
// we omit initial_comment and let blocks render instead.
159+
...(blocks && blocks.length > 0 ? { blocks } : { initial_comment: text }),
156160
...(threadTs && { thread_ts: threadTs }),
157161
}),
158162
})
@@ -295,7 +299,14 @@ export async function sendSlackMessage(
295299
}
296300

297301
// Complete file upload with thread support
298-
const completeData = await completeSlackFileUpload(fileIds, channel, text, accessToken, threadTs)
302+
const completeData = await completeSlackFileUpload(
303+
fileIds,
304+
channel,
305+
text,
306+
accessToken,
307+
threadTs,
308+
blocks
309+
)
299310

300311
if (!completeData.ok) {
301312
logger.error(`[${requestId}] Failed to complete upload:`, completeData.error)

apps/sim/tools/google_drive/list.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,11 @@ export const listTool: ToolConfig<GoogleDriveToolParams, GoogleDriveListResponse
6666
const escapeQueryValue = (value: string): string =>
6767
value.replace(/\\/g, '\\\\').replace(/'/g, "\\'")
6868

69-
// Build the query conditions
70-
const conditions = ['trashed = false'] // Always exclude trashed files
69+
// Build the query conditions. `params.query` here is a plain-text name
70+
// search term (wrapped in `name contains '...'` below), not Google Drive
71+
// query syntax — so there's no caller-supplied `trashed` predicate to
72+
// honour. Always exclude trashed files.
73+
const conditions: string[] = ['trashed = false']
7174
const folderId = (params.folderId || params.folderSelector)?.trim()
7275
if (folderId) {
7376
const escapedFolderId = escapeQueryValue(folderId)

apps/sim/tools/google_drive/search.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,14 @@ export const searchTool: ToolConfig<GoogleDriveSearchParams, GoogleDriveSearchRe
6464
url.searchParams.append('includeItemsFromAllDrives', 'true')
6565

6666
// The query is passed directly as Google Drive query syntax
67-
const conditions = ['trashed = false']
68-
if (params.query?.trim()) {
69-
conditions.push(params.query.trim())
67+
const userQuery = params.query?.trim()
68+
const userSpecifiesTrashed = userQuery ? /\btrashed\s*=/.test(userQuery) : false
69+
const conditions: string[] = []
70+
if (!userSpecifiesTrashed) {
71+
conditions.push('trashed = false')
72+
}
73+
if (userQuery) {
74+
conditions.push(userQuery)
7075
}
7176
url.searchParams.append('q', conditions.join(' and '))
7277

apps/sim/tools/slack/get_message.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import { createLogger } from '@sim/logger'
12
import type { SlackGetMessageParams, SlackGetMessageResponse } from '@/tools/slack/types'
23
import { MESSAGE_OUTPUT_PROPERTIES } from '@/tools/slack/types'
34
import type { ToolConfig } from '@/tools/types'
45

6+
const logger = createLogger('SlackGetMessageTool')
7+
58
export const slackGetMessageTool: ToolConfig<SlackGetMessageParams, SlackGetMessageResponse> = {
69
id: 'slack_get_message',
710
name: 'Slack Get Message',
@@ -49,11 +52,10 @@ export const slackGetMessageTool: ToolConfig<SlackGetMessageParams, SlackGetMess
4952

5053
request: {
5154
url: (params: SlackGetMessageParams) => {
52-
const url = new URL('https://slack.com/api/conversations.history')
55+
const url = new URL('https://slack.com/api/conversations.replies')
5356
url.searchParams.append('channel', params.channel?.trim() ?? '')
54-
url.searchParams.append('oldest', params.timestamp?.trim() ?? '')
57+
url.searchParams.append('ts', params.timestamp?.trim() ?? '')
5558
url.searchParams.append('limit', '1')
56-
url.searchParams.append('inclusive', 'true')
5759
return url.toString()
5860
},
5961
method: 'GET',
@@ -63,8 +65,9 @@ export const slackGetMessageTool: ToolConfig<SlackGetMessageParams, SlackGetMess
6365
}),
6466
},
6567

66-
transformResponse: async (response: Response) => {
68+
transformResponse: async (response: Response, params?: SlackGetMessageParams) => {
6769
const data = await response.json()
70+
const requestedTs = params?.timestamp?.trim() ?? ''
6871

6972
if (!data.ok) {
7073
if (data.error === 'missing_scope') {
@@ -78,15 +81,25 @@ export const slackGetMessageTool: ToolConfig<SlackGetMessageParams, SlackGetMess
7881
if (data.error === 'channel_not_found') {
7982
throw new Error('Channel not found. Please check the channel ID.')
8083
}
84+
if (data.error === 'message_not_found' || data.error === 'thread_not_found') {
85+
throw new Error(`Message not found at timestamp ${requestedTs}`)
86+
}
8187
throw new Error(data.error || 'Failed to get message from Slack')
8288
}
8389

8490
const messages = data.messages || []
8591
if (messages.length === 0) {
86-
throw new Error('Message not found')
92+
throw new Error(`Message not found at timestamp ${requestedTs}`)
8793
}
8894

8995
const msg = messages[0]
96+
if (requestedTs && msg.ts !== requestedTs) {
97+
logger.warn('Slack returned a message with a different timestamp than requested', {
98+
requestedTs,
99+
returnedTs: msg.ts,
100+
})
101+
throw new Error(`Message not found at timestamp ${requestedTs}`)
102+
}
90103
const message = {
91104
type: msg.type ?? 'message',
92105
ts: msg.ts,

0 commit comments

Comments
 (0)