Skip to content

Commit 419bf2a

Browse files
committed
Fixes
1 parent 48db52a commit 419bf2a

3 files changed

Lines changed: 22 additions & 40 deletions

File tree

apps/sim/executor/handlers/mothership/mothership-handler.test.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,6 @@ describe('MothershipBlockHandler', () => {
247247
files: [
248248
{
249249
name: 'notes.txt',
250-
path: '/api/files/serve/workspace/workspace-1/notes.txt',
251250
key: 'workspace/workspace-1/notes.txt',
252251
size: 16,
253252
type: 'text/plain',
@@ -261,14 +260,14 @@ describe('MothershipBlockHandler', () => {
261260
conversationId: 'chat-uuid',
262261
})
263262
expect(mockReadUserFileContent).toHaveBeenCalledWith(
264-
{
265-
id: 'workspace/workspace-1/notes.txt',
263+
expect.objectContaining({
264+
id: expect.stringMatching(/^file-/),
266265
key: 'workspace/workspace-1/notes.txt',
267266
name: 'notes.txt',
268-
url: '/api/files/serve/workspace/workspace-1/notes.txt',
267+
url: '',
269268
size: 16,
270269
type: 'text/plain',
271-
},
270+
}),
272271
expect.objectContaining({
273272
encoding: 'base64',
274273
userId: 'user-1',

apps/sim/executor/handlers/mothership/mothership-handler.ts

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@ import { toError } from '@sim/utils/errors'
33
import { generateId } from '@sim/utils/id'
44
import { isExecutionCancelled, isRedisCancellationEnabled } from '@/lib/execution/cancellation'
55
import { readUserFileContent } from '@/lib/execution/payloads/materialization.server'
6-
import { createFileContent, type MessageContent } from '@/lib/uploads/utils/file-utils'
6+
import {
7+
createFileContentFromBase64,
8+
type MessageContent,
9+
processSingleFileToUserFile,
10+
type RawFileInput,
11+
} from '@/lib/uploads/utils/file-utils'
712
import type { BlockOutput } from '@/blocks/types'
813
import { normalizeFileInput } from '@/blocks/utils'
914
import { BlockType } from '@/executor/constants'
10-
import type { BlockHandler, ExecutionContext, UserFile } from '@/executor/types'
15+
import type { BlockHandler, ExecutionContext } from '@/executor/types'
1116
import { buildAPIUrl, buildAuthHeaders, extractAPIErrorMessage } from '@/executor/utils/http'
1217
import type { SerializedBlock } from '@/serializer/types'
1318

@@ -19,35 +24,6 @@ type MothershipFileAttachment = MessageContent & {
1924
filename?: string
2025
}
2126

22-
function toUserFile(file: object): UserFile {
23-
const candidate = file as Record<string, unknown>
24-
const key = typeof candidate.key === 'string' ? candidate.key : ''
25-
const name = typeof candidate.name === 'string' ? candidate.name : ''
26-
const url =
27-
typeof candidate.url === 'string'
28-
? candidate.url
29-
: typeof candidate.path === 'string'
30-
? candidate.path
31-
: key
32-
const size = typeof candidate.size === 'number' ? candidate.size : Number(candidate.size)
33-
const type = typeof candidate.type === 'string' ? candidate.type : ''
34-
const id = typeof candidate.id === 'string' ? candidate.id : key
35-
36-
if (!id || !key || !name || !url || !Number.isFinite(size) || !type) {
37-
throw new Error('Mothership attachment must include file name, key, url/path, size, and type.')
38-
}
39-
40-
return {
41-
id,
42-
key,
43-
name,
44-
url,
45-
size,
46-
type,
47-
...(typeof candidate.context === 'string' ? { context: candidate.context } : {}),
48-
}
49-
}
50-
5127
async function buildMothershipFileAttachments(
5228
filesInput: unknown,
5329
ctx: ExecutionContext,
@@ -64,7 +40,7 @@ async function buildMothershipFileAttachments(
6440

6541
const attachments: MothershipFileAttachment[] = []
6642
for (const file of files) {
67-
const userFile = toUserFile(file)
43+
const userFile = processSingleFileToUserFile(file as RawFileInput, requestId, logger)
6844
const base64 = await readUserFileContent(userFile, {
6945
encoding: 'base64',
7046
userId: ctx.userId,
@@ -79,7 +55,7 @@ async function buildMothershipFileAttachments(
7955
maxSourceBytes: MAX_MOTHERSHIP_ATTACHMENT_BYTES,
8056
})
8157

82-
const content = createFileContent(Buffer.from(base64, 'base64'), userFile.type)
58+
const content = createFileContentFromBase64(base64, userFile.type)
8359
if (!content) {
8460
throw new Error(`File type is not supported for Mothership attachments: ${userFile.name}`)
8561
}

apps/sim/lib/uploads/utils/file-utils.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,13 @@ export function bufferToBase64(buffer: Buffer): string {
147147
* Create message content from file data
148148
*/
149149
export function createFileContent(fileBuffer: Buffer, mimeType: string): MessageContent | null {
150+
return createFileContentFromBase64(bufferToBase64(fileBuffer), mimeType)
151+
}
152+
153+
/**
154+
* Create message content from base64-encoded file data.
155+
*/
156+
export function createFileContentFromBase64(base64: string, mimeType: string): MessageContent | null {
150157
// SVG is XML text — Claude only supports raster image formats (JPEG, PNG, GIF, WebP),
151158
// so send SVGs as an XML document instead
152159
if (mimeType.toLowerCase() === 'image/svg+xml') {
@@ -155,7 +162,7 @@ export function createFileContent(fileBuffer: Buffer, mimeType: string): Message
155162
source: {
156163
type: 'base64',
157164
media_type: 'text/xml',
158-
data: bufferToBase64(fileBuffer),
165+
data: base64,
159166
},
160167
}
161168
}
@@ -174,7 +181,7 @@ export function createFileContent(fileBuffer: Buffer, mimeType: string): Message
174181
source: {
175182
type: 'base64',
176183
media_type: mimeType,
177-
data: bufferToBase64(fileBuffer),
184+
data: base64,
178185
},
179186
}
180187
}

0 commit comments

Comments
 (0)