Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions apps/sim/app/api/tools/file/manage/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ensureAbsoluteUrl } from '@/lib/core/utils/urls'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import {
fetchWorkspaceFileBuffer,
getWorkspaceFile,
getWorkspaceFileByName,
updateWorkspaceFileContent,
uploadWorkspaceFile,
Expand Down Expand Up @@ -40,6 +41,51 @@ export const POST = withRouteHandler(async (request: NextRequest) => {

try {
switch (body.operation) {
case 'get': {
const { fileId, fileInput } = body
const selectedFileId =
fileId ||
(fileInput && typeof fileInput === 'object' && !Array.isArray(fileInput)
? typeof fileInput.id === 'string'
? fileInput.id
: typeof fileInput.fileId === 'string'
? fileInput.fileId
: ''
: '')

if (!selectedFileId) {
return NextResponse.json({ success: false, error: 'File is required' }, { status: 400 })
}

const file = await getWorkspaceFile(workspaceId, selectedFileId)
if (!file) {
return NextResponse.json(
{ success: false, error: `File not found: "${selectedFileId}"` },
{ status: 404 }
)
}

logger.info('File retrieved', {
fileId: file.id,
name: file.name,
})

return NextResponse.json({
success: true,
data: {
file: {
id: file.id,
name: file.name,
url: ensureAbsoluteUrl(file.path),
size: file.size,
type: file.type,
key: file.key,
context: 'workspace',
},
},
})
}
Comment thread
Sg312 marked this conversation as resolved.

case 'write': {
const { fileName, content, contentType } = body
const mimeType = contentType || getMimeTypeFromExtension(getFileExtension(fileName))
Expand Down
54 changes: 52 additions & 2 deletions apps/sim/blocks/blocks/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ export const FileV3Block: BlockConfig<FileParserV3Output> = {
type: 'dropdown' as SubBlockType,
options: [
{ label: 'Read', id: 'file_parser_v3' },
{ label: 'Get', id: 'file_get' },
{ label: 'Write', id: 'file_write' },
{ label: 'Append', id: 'file_append' },
],
Expand Down Expand Up @@ -294,6 +295,28 @@ export const FileV3Block: BlockConfig<FileParserV3Output> = {
required: { field: 'operation', value: 'file_parser_v3' },
condition: { field: 'operation', value: 'file_parser_v3' },
},
{
id: 'getFile',
title: 'File',
type: 'file-upload' as SubBlockType,
canonicalParamId: 'getFileInput',
acceptedTypes: '*',
placeholder: 'Select a workspace file',
multiple: false,
mode: 'basic',
condition: { field: 'operation', value: 'file_get' },
required: { field: 'operation', value: 'file_get' },
},
{
id: 'getFileId',
title: 'File ID',
type: 'short-input' as SubBlockType,
canonicalParamId: 'getFileInput',
placeholder: 'Workspace file ID',
mode: 'advanced',
condition: { field: 'operation', value: 'file_get' },
required: { field: 'operation', value: 'file_get' },
},
{
id: 'fileName',
title: 'File Name',
Expand Down Expand Up @@ -349,7 +372,7 @@ export const FileV3Block: BlockConfig<FileParserV3Output> = {
},
],
tools: {
access: ['file_parser_v3', 'file_write', 'file_append'],
access: ['file_parser_v3', 'file_get', 'file_write', 'file_append'],
config: {
tool: (params) => params.operation || 'file_parser_v3',
params: (params) => {
Expand Down Expand Up @@ -390,6 +413,25 @@ export const FileV3Block: BlockConfig<FileParserV3Output> = {
}
}

if (operation === 'file_get') {
const getInput = params.getFileInput
if (!getInput) {
throw new Error('File is required for get')
}

if (typeof getInput === 'string') {
return {
fileId: getInput.trim(),
workspaceId: params._context?.workspaceId,
}
}

return {
fileInput: normalizeFileInput(getInput, { single: true }),
workspaceId: params._context?.workspaceId,
}
}

const fileInput = params.fileInput
if (!fileInput) {
logger.error('No file input provided')
Expand Down Expand Up @@ -428,9 +470,13 @@ export const FileV3Block: BlockConfig<FileParserV3Output> = {
},
},
inputs: {
operation: { type: 'string', description: 'Operation to perform (read, write, or append)' },
operation: {
type: 'string',
description: 'Operation to perform (read, get, write, or append)',
},
fileInput: { type: 'json', description: 'File input for read' },
fileType: { type: 'string', description: 'File type for read' },
getFileInput: { type: 'json', description: 'Selected file or workspace file ID for get' },
fileName: { type: 'string', description: 'Name for a new file (write)' },
content: { type: 'string', description: 'File content to write' },
contentType: { type: 'string', description: 'MIME content type for write' },
Expand All @@ -446,6 +492,10 @@ export const FileV3Block: BlockConfig<FileParserV3Output> = {
type: 'string',
description: 'All file contents merged into a single text string (read)',
},
file: {
type: 'file',
description: 'Workspace file object (get)',
},
id: {
type: 'string',
description: 'File ID (write)',
Expand Down
14 changes: 13 additions & 1 deletion apps/sim/lib/api/contracts/tools/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,21 @@ export const fileManageAppendBodySchema = z.object({
content: z.string({ error: 'content is required for append operation' }),
})

export const fileManageBodySchema = z.discriminatedUnion('operation', [
export const fileManageGetBodySchema = z
.object({
operation: z.literal('get'),
workspaceId: z.string().min(1).optional(),
fileId: z.string().min(1).optional(),
fileInput: z.any().optional(),
})
.refine((data) => data.fileId !== undefined || data.fileInput !== undefined, {
message: 'Either fileId or fileInput is required for get operation',
})

export const fileManageBodySchema = z.union([
fileManageWriteBodySchema,
fileManageAppendBodySchema,
fileManageGetBodySchema,
])

export const fileManageContract = defineRouteContract({
Expand Down
54 changes: 54 additions & 0 deletions apps/sim/tools/file/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { ToolConfig, ToolResponse, WorkflowToolExecutionContext } from '@/tools/types'

interface FileGetParams {
fileId?: string
fileInput?: unknown
workspaceId?: string
_context?: WorkflowToolExecutionContext
}

export const fileGetTool: ToolConfig<FileGetParams, ToolResponse> = {
id: 'file_get',
name: 'File Get',
description: 'Get a workspace file object from a selected file or canonical workspace file ID.',
version: '1.0.0',

params: {
fileId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Canonical workspace file ID.',
},
fileInput: {
type: 'file',
required: false,
visibility: 'user-only',
description: 'Selected workspace file object.',
},
},

request: {
url: '/api/tools/file/manage',
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'get',
fileId: params.fileId,
fileInput: params.fileInput,
workspaceId: params.workspaceId || params._context?.workspaceId,
}),
},

transformResponse: async (response) => {
const data = await response.json()
if (!response.ok || !data.success) {
return { success: false, output: {}, error: data.error || 'Failed to get file' }
}
return { success: true, output: data.data }
},

outputs: {
file: { type: 'file', description: 'Workspace file object' },
},
}
1 change: 1 addition & 0 deletions apps/sim/tools/file/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { fileParserTool, fileParserV2Tool, fileParserV3Tool } from '@/tools/file/parser'

export { fileAppendTool } from '@/tools/file/append'
export { fileGetTool } from '@/tools/file/get'
export { fileWriteTool } from '@/tools/file/write'

export const fileParseTool = fileParserTool
Expand Down
2 changes: 2 additions & 0 deletions apps/sim/tools/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,7 @@ import {
} from '@/tools/fathom'
import {
fileAppendTool,
fileGetTool,
fileParserV2Tool,
fileParserV3Tool,
fileParseTool,
Expand Down Expand Up @@ -3213,6 +3214,7 @@ export const tools: Record<string, ToolConfig> = {
file_parser_v2: fileParserV2Tool,
file_parser_v3: fileParserV3Tool,
file_append: fileAppendTool,
file_get: fileGetTool,
file_write: fileWriteTool,
firecrawl_scrape: firecrawlScrapeTool,
firecrawl_search: firecrawlSearchTool,
Expand Down
Loading