Skip to content

Commit ed1ca6e

Browse files
committed
user files should be passed through
1 parent 4f2b5a5 commit ed1ca6e

File tree

2 files changed

+40
-26
lines changed

2 files changed

+40
-26
lines changed

apps/sim/app/api/tools/stt/route.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
secureFetchWithPinnedIP,
77
validateUrlWithDNS,
88
} from '@/lib/core/security/input-validation.server'
9-
import { isInternalFileUrl } from '@/lib/uploads/utils/file-utils'
9+
import { getMimeTypeFromExtension, isInternalFileUrl } from '@/lib/uploads/utils/file-utils'
1010
import {
1111
downloadFileFromStorage,
1212
resolveInternalFileUrl,
@@ -89,7 +89,10 @@ export async function POST(request: NextRequest) {
8989

9090
audioBuffer = await downloadFileFromStorage(file, requestId, logger)
9191
audioFileName = file.name
92-
audioMimeType = file.type
92+
// file.type may be missing if the file came from a block that doesn't preserve it
93+
// Infer from filename extension as fallback
94+
const ext = file.name.split('.').pop()?.toLowerCase() || ''
95+
audioMimeType = file.type || getMimeTypeFromExtension(ext)
9396
} else if (body.audioFileReference) {
9497
if (Array.isArray(body.audioFileReference) && body.audioFileReference.length !== 1) {
9598
return NextResponse.json(
@@ -104,7 +107,9 @@ export async function POST(request: NextRequest) {
104107

105108
audioBuffer = await downloadFileFromStorage(file, requestId, logger)
106109
audioFileName = file.name
107-
audioMimeType = file.type
110+
111+
const ext = file.name.split('.').pop()?.toLowerCase() || ''
112+
audioMimeType = file.type || getMimeTypeFromExtension(ext)
108113
} else if (body.audioUrl) {
109114
logger.info(`[${requestId}] Downloading from URL: ${body.audioUrl}`)
110115

apps/sim/executor/utils/file-tool-processor.ts

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createLogger } from '@sim/logger'
2+
import { isUserFile } from '@/lib/core/utils/user-file'
23
import { uploadExecutionFile, uploadFileFromRawData } from '@/lib/uploads/contexts/execution'
34
import { downloadFileFromUrl } from '@/lib/uploads/utils/file-utils.server'
45
import type { ExecutionContext, UserFile } from '@/executor/types'
@@ -94,31 +95,39 @@ export class FileToolProcessor {
9495
}
9596

9697
/**
97-
* Convert various file data formats to UserFile by storing in execution filesystem
98+
* Convert various file data formats to UserFile by storing in execution filesystem.
99+
* If the input is already a UserFile, returns it unchanged.
98100
*/
99101
private static async processFileData(
100-
fileData: ToolFileData,
102+
fileData: ToolFileData | UserFile,
101103
context: ExecutionContext
102104
): Promise<UserFile> {
105+
// If already a UserFile (e.g., from tools that handle their own file storage),
106+
// return it directly without re-processing
107+
if (isUserFile(fileData)) {
108+
return fileData as UserFile
109+
}
110+
111+
const data = fileData as ToolFileData
103112
try {
104113
let buffer: Buffer | null = null
105114

106-
if (Buffer.isBuffer(fileData.data)) {
107-
buffer = fileData.data
115+
if (Buffer.isBuffer(data.data)) {
116+
buffer = data.data
108117
} else if (
109-
fileData.data &&
110-
typeof fileData.data === 'object' &&
111-
'type' in fileData.data &&
112-
'data' in fileData.data
118+
data.data &&
119+
typeof data.data === 'object' &&
120+
'type' in data.data &&
121+
'data' in data.data
113122
) {
114-
const serializedBuffer = fileData.data as { type: string; data: number[] }
123+
const serializedBuffer = data.data as { type: string; data: number[] }
115124
if (serializedBuffer.type === 'Buffer' && Array.isArray(serializedBuffer.data)) {
116125
buffer = Buffer.from(serializedBuffer.data)
117126
} else {
118-
throw new Error(`Invalid serialized buffer format for ${fileData.name}`)
127+
throw new Error(`Invalid serialized buffer format for ${data.name}`)
119128
}
120-
} else if (typeof fileData.data === 'string' && fileData.data) {
121-
let base64Data = fileData.data
129+
} else if (typeof data.data === 'string' && data.data) {
130+
let base64Data = data.data
122131

123132
if (base64Data.includes('-') || base64Data.includes('_')) {
124133
base64Data = base64Data.replace(/-/g, '+').replace(/_/g, '/')
@@ -127,13 +136,13 @@ export class FileToolProcessor {
127136
buffer = Buffer.from(base64Data, 'base64')
128137
}
129138

130-
if (!buffer && fileData.url) {
131-
buffer = await downloadFileFromUrl(fileData.url)
139+
if (!buffer && data.url) {
140+
buffer = await downloadFileFromUrl(data.url)
132141
}
133142

134143
if (buffer) {
135144
if (buffer.length === 0) {
136-
throw new Error(`File '${fileData.name}' has zero bytes`)
145+
throw new Error(`File '${data.name}' has zero bytes`)
137146
}
138147

139148
return await uploadExecutionFile(
@@ -143,23 +152,23 @@ export class FileToolProcessor {
143152
executionId: context.executionId || '',
144153
},
145154
buffer,
146-
fileData.name,
147-
fileData.mimeType,
155+
data.name,
156+
data.mimeType,
148157
context.userId
149158
)
150159
}
151160

152-
if (!fileData.data) {
161+
if (!data.data) {
153162
throw new Error(
154-
`File data for '${fileData.name}' must have either 'data' (Buffer/base64) or 'url' property`
163+
`File data for '${data.name}' must have either 'data' (Buffer/base64) or 'url' property`
155164
)
156165
}
157166

158167
return uploadFileFromRawData(
159168
{
160-
name: fileData.name,
161-
data: fileData.data,
162-
mimeType: fileData.mimeType,
169+
name: data.name,
170+
data: data.data,
171+
mimeType: data.mimeType,
163172
},
164173
{
165174
workspaceId: context.workspaceId || '',
@@ -169,7 +178,7 @@ export class FileToolProcessor {
169178
context.userId
170179
)
171180
} catch (error) {
172-
logger.error(`Error processing file data for '${fileData.name}':`, error)
181+
logger.error(`Error processing file data for '${data.name}':`, error)
173182
throw error
174183
}
175184
}

0 commit comments

Comments
 (0)