Skip to content

Commit f99961e

Browse files
committed
File block get
1 parent 4de955d commit f99961e

6 files changed

Lines changed: 147 additions & 2 deletions

File tree

apps/sim/app/api/tools/file/manage/route.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ensureAbsoluteUrl } from '@/lib/core/utils/urls'
88
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
99
import {
1010
fetchWorkspaceFileBuffer,
11+
getWorkspaceFile,
1112
getWorkspaceFileByName,
1213
updateWorkspaceFileContent,
1314
uploadWorkspaceFile,
@@ -40,6 +41,38 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
4041

4142
try {
4243
switch (body.operation) {
44+
case 'get': {
45+
const { fileId, fileInput } = body
46+
47+
if (fileInput && typeof fileInput === 'object' && !Array.isArray(fileInput)) {
48+
return NextResponse.json({ success: true, data: { file: fileInput } })
49+
}
50+
51+
if (!fileId) {
52+
return NextResponse.json({ success: false, error: 'File is required' }, { status: 400 })
53+
}
54+
55+
const file = await getWorkspaceFile(workspaceId, fileId)
56+
if (!file) {
57+
return NextResponse.json({ success: false, error: `File not found: "${fileId}"` }, { status: 404 })
58+
}
59+
60+
return NextResponse.json({
61+
success: true,
62+
data: {
63+
file: {
64+
id: file.id,
65+
name: file.name,
66+
url: ensureAbsoluteUrl(file.path),
67+
size: file.size,
68+
type: file.type,
69+
key: file.key,
70+
context: 'workspace',
71+
},
72+
},
73+
})
74+
}
75+
4376
case 'write': {
4477
const { fileName, content, contentType } = body
4578
const mimeType = contentType || getMimeTypeFromExtension(getFileExtension(fileName))

apps/sim/blocks/blocks/file.ts

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ export const FileV3Block: BlockConfig<FileParserV3Output> = {
266266
type: 'dropdown' as SubBlockType,
267267
options: [
268268
{ label: 'Read', id: 'file_parser_v3' },
269+
{ label: 'Get', id: 'file_get' },
269270
{ label: 'Write', id: 'file_write' },
270271
{ label: 'Append', id: 'file_append' },
271272
],
@@ -294,6 +295,28 @@ export const FileV3Block: BlockConfig<FileParserV3Output> = {
294295
required: { field: 'operation', value: 'file_parser_v3' },
295296
condition: { field: 'operation', value: 'file_parser_v3' },
296297
},
298+
{
299+
id: 'getFile',
300+
title: 'File',
301+
type: 'file-upload' as SubBlockType,
302+
canonicalParamId: 'getFileInput',
303+
acceptedTypes: '*',
304+
placeholder: 'Select a workspace file',
305+
multiple: false,
306+
mode: 'basic',
307+
condition: { field: 'operation', value: 'file_get' },
308+
required: { field: 'operation', value: 'file_get' },
309+
},
310+
{
311+
id: 'getFileId',
312+
title: 'File ID',
313+
type: 'short-input' as SubBlockType,
314+
canonicalParamId: 'getFileInput',
315+
placeholder: 'Workspace file ID',
316+
mode: 'advanced',
317+
condition: { field: 'operation', value: 'file_get' },
318+
required: { field: 'operation', value: 'file_get' },
319+
},
297320
{
298321
id: 'fileName',
299322
title: 'File Name',
@@ -349,7 +372,7 @@ export const FileV3Block: BlockConfig<FileParserV3Output> = {
349372
},
350373
],
351374
tools: {
352-
access: ['file_parser_v3', 'file_write', 'file_append'],
375+
access: ['file_parser_v3', 'file_get', 'file_write', 'file_append'],
353376
config: {
354377
tool: (params) => params.operation || 'file_parser_v3',
355378
params: (params) => {
@@ -390,6 +413,25 @@ export const FileV3Block: BlockConfig<FileParserV3Output> = {
390413
}
391414
}
392415

416+
if (operation === 'file_get') {
417+
const getInput = params.getFileInput
418+
if (!getInput) {
419+
throw new Error('File is required for get')
420+
}
421+
422+
if (typeof getInput === 'string') {
423+
return {
424+
fileId: getInput.trim(),
425+
workspaceId: params._context?.workspaceId,
426+
}
427+
}
428+
429+
return {
430+
fileInput: normalizeFileInput(getInput, { single: true }),
431+
workspaceId: params._context?.workspaceId,
432+
}
433+
}
434+
393435
const fileInput = params.fileInput
394436
if (!fileInput) {
395437
logger.error('No file input provided')
@@ -428,9 +470,10 @@ export const FileV3Block: BlockConfig<FileParserV3Output> = {
428470
},
429471
},
430472
inputs: {
431-
operation: { type: 'string', description: 'Operation to perform (read, write, or append)' },
473+
operation: { type: 'string', description: 'Operation to perform (read, get, write, or append)' },
432474
fileInput: { type: 'json', description: 'File input for read' },
433475
fileType: { type: 'string', description: 'File type for read' },
476+
getFileInput: { type: 'json', description: 'Selected file or workspace file ID for get' },
434477
fileName: { type: 'string', description: 'Name for a new file (write)' },
435478
content: { type: 'string', description: 'File content to write' },
436479
contentType: { type: 'string', description: 'MIME content type for write' },
@@ -446,6 +489,10 @@ export const FileV3Block: BlockConfig<FileParserV3Output> = {
446489
type: 'string',
447490
description: 'All file contents merged into a single text string (read)',
448491
},
492+
file: {
493+
type: 'file',
494+
description: 'Workspace file object (get)',
495+
},
449496
id: {
450497
type: 'string',
451498
description: 'File ID (write)',

apps/sim/lib/api/contracts/tools/file.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,17 @@ export const fileManageAppendBodySchema = z.object({
2222
content: z.string({ error: 'content is required for append operation' }),
2323
})
2424

25+
export const fileManageGetBodySchema = z.object({
26+
operation: z.literal('get'),
27+
workspaceId: z.string().min(1).optional(),
28+
fileId: z.string().min(1).optional(),
29+
fileInput: z.any().optional(),
30+
})
31+
2532
export const fileManageBodySchema = z.discriminatedUnion('operation', [
2633
fileManageWriteBodySchema,
2734
fileManageAppendBodySchema,
35+
fileManageGetBodySchema,
2836
])
2937

3038
export const fileManageContract = defineRouteContract({

apps/sim/tools/file/get.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import type { ToolConfig, ToolResponse, WorkflowToolExecutionContext } from '@/tools/types'
2+
3+
interface FileGetParams {
4+
fileId?: string
5+
fileInput?: unknown
6+
workspaceId?: string
7+
_context?: WorkflowToolExecutionContext
8+
}
9+
10+
export const fileGetTool: ToolConfig<FileGetParams, ToolResponse> = {
11+
id: 'file_get',
12+
name: 'File Get',
13+
description: 'Get a workspace file object from a selected file or canonical workspace file ID.',
14+
version: '1.0.0',
15+
16+
params: {
17+
fileId: {
18+
type: 'string',
19+
required: false,
20+
visibility: 'user-or-llm',
21+
description: 'Canonical workspace file ID.',
22+
},
23+
fileInput: {
24+
type: 'file',
25+
required: false,
26+
visibility: 'user-only',
27+
description: 'Selected workspace file object.',
28+
},
29+
},
30+
31+
request: {
32+
url: '/api/tools/file/manage',
33+
method: 'POST',
34+
headers: () => ({ 'Content-Type': 'application/json' }),
35+
body: (params) => ({
36+
operation: 'get',
37+
fileId: params.fileId,
38+
fileInput: params.fileInput,
39+
workspaceId: params.workspaceId || params._context?.workspaceId,
40+
}),
41+
},
42+
43+
transformResponse: async (response) => {
44+
const data = await response.json()
45+
if (!response.ok || !data.success) {
46+
return { success: false, output: {}, error: data.error || 'Failed to get file' }
47+
}
48+
return { success: true, output: data.data }
49+
},
50+
51+
outputs: {
52+
file: { type: 'file', description: 'Workspace file object' },
53+
},
54+
}

apps/sim/tools/file/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { fileParserTool, fileParserV2Tool, fileParserV3Tool } from '@/tools/file/parser'
22

33
export { fileAppendTool } from '@/tools/file/append'
4+
export { fileGetTool } from '@/tools/file/get'
45
export { fileWriteTool } from '@/tools/file/write'
56

67
export const fileParseTool = fileParserTool

apps/sim/tools/registry.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,7 @@ import {
643643
} from '@/tools/fathom'
644644
import {
645645
fileAppendTool,
646+
fileGetTool,
646647
fileParserV2Tool,
647648
fileParserV3Tool,
648649
fileParseTool,
@@ -3213,6 +3214,7 @@ export const tools: Record<string, ToolConfig> = {
32133214
file_parser_v2: fileParserV2Tool,
32143215
file_parser_v3: fileParserV3Tool,
32153216
file_append: fileAppendTool,
3217+
file_get: fileGetTool,
32163218
file_write: fileWriteTool,
32173219
firecrawl_scrape: firecrawlScrapeTool,
32183220
firecrawl_search: firecrawlSearchTool,

0 commit comments

Comments
 (0)