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
145 changes: 139 additions & 6 deletions apps/sim/blocks/blocks/mistral_parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,16 @@ export const MistralParseBlock: BlockConfig<MistralParserOutput> = {
},
}

/**
* V2 Block - Restored from main branch for backwards compatibility
* Hidden from toolbar, uses filePath subblock ID for advanced mode
*/
export const MistralParseV2Block: BlockConfig<MistralParserOutput> = {
...MistralParseBlock,
type: 'mistral_parse_v2',
name: 'Mistral Parser',
description: 'Extract text from PDF documents',
hideFromToolbar: false,
hideFromToolbar: true,
subBlocks: [
{
id: 'fileUpload',
Expand All @@ -159,16 +163,14 @@ export const MistralParseV2Block: BlockConfig<MistralParserOutput> = {
placeholder: 'Upload a PDF document',
mode: 'basic',
maxSize: 50,
required: true,
},
{
id: 'fileReference',
title: 'File Reference',
id: 'filePath',
title: 'PDF Document',
type: 'short-input' as SubBlockType,
canonicalParamId: 'document',
placeholder: 'File reference from previous block',
placeholder: 'Document URL',
mode: 'advanced',
required: true,
},
{
id: 'resultType',
Expand Down Expand Up @@ -213,6 +215,137 @@ export const MistralParseV2Block: BlockConfig<MistralParserOutput> = {
resultType: params.resultType || 'markdown',
}

// Original V2 pattern: fileUpload (basic) or filePath (advanced) or document (wired)
const documentInput = params.fileUpload || params.filePath || params.document
if (!documentInput) {
throw new Error('PDF document is required')
}
// Smart handling: object → fileUpload param, string → filePath param
if (typeof documentInput === 'object') {
parameters.fileUpload = documentInput
} else if (typeof documentInput === 'string') {
parameters.filePath = documentInput.trim()
}

let pagesArray: number[] | undefined
if (params.pages && params.pages.trim() !== '') {
try {
pagesArray = params.pages
.split(',')
.map((p: string) => p.trim())
.filter((p: string) => p.length > 0)
.map((p: string) => {
const num = Number.parseInt(p, 10)
if (Number.isNaN(num) || num < 0) {
throw new Error(`Invalid page number: ${p}`)
}
return num
})

if (pagesArray && pagesArray.length === 0) {
pagesArray = undefined
}
} catch (error: unknown) {
const errorMessage = error instanceof Error ? error.message : String(error)
throw new Error(`Page number format error: ${errorMessage}`)
}
}

if (pagesArray && pagesArray.length > 0) {
parameters.pages = pagesArray
}

return parameters
},
},
},
inputs: {
document: { type: 'json', description: 'Document input (file upload or URL reference)' },
filePath: { type: 'string', description: 'PDF document URL (advanced mode)' },
fileUpload: { type: 'json', description: 'Uploaded PDF file (basic mode)' },
apiKey: { type: 'string', description: 'Mistral API key' },
resultType: { type: 'string', description: 'Output format type' },
pages: { type: 'string', description: 'Page selection' },
},
outputs: {
pages: { type: 'array', description: 'Array of page objects from Mistral OCR' },
model: { type: 'string', description: 'Mistral OCR model identifier' },
usage_info: { type: 'json', description: 'Usage statistics from the API' },
document_annotation: { type: 'string', description: 'Structured annotation data' },
},
}

/**
* V3 Block - New file handling pattern with UserFile normalization
* Uses fileReference subblock ID with canonicalParamId for proper file handling
*/
export const MistralParseV3Block: BlockConfig<MistralParserOutput> = {
...MistralParseBlock,
type: 'mistral_parse_v3',
name: 'Mistral Parser',
description: 'Extract text from PDF documents',
hideFromToolbar: false,
subBlocks: [
{
id: 'fileUpload',
title: 'PDF Document',
type: 'file-upload' as SubBlockType,
canonicalParamId: 'document',
acceptedTypes: 'application/pdf',
placeholder: 'Upload a PDF document',
mode: 'basic',
maxSize: 50,
required: true,
},
{
id: 'fileReference',
title: 'File Reference',
type: 'short-input' as SubBlockType,
canonicalParamId: 'document',
placeholder: 'File reference from previous block',
mode: 'advanced',
required: true,
},
{
id: 'resultType',
title: 'Output Format',
type: 'dropdown',
options: [
{ id: 'markdown', label: 'Markdown' },
{ id: 'text', label: 'Plain Text' },
{ id: 'json', label: 'JSON' },
],
},
{
id: 'pages',
title: 'Specific Pages',
type: 'short-input',
placeholder: 'e.g. 0,1,2 (leave empty for all pages)',
},
{
id: 'apiKey',
title: 'API Key',
type: 'short-input' as SubBlockType,
placeholder: 'Enter your Mistral API key',
password: true,
required: true,
},
],
tools: {
access: ['mistral_parser_v3'],
config: {
tool: () => 'mistral_parser_v3',
params: (params) => {
if (!params || !params.apiKey || params.apiKey.trim() === '') {
throw new Error('Mistral API key is required')
}

const parameters: Record<string, unknown> = {
apiKey: params.apiKey.trim(),
resultType: params.resultType || 'markdown',
}

// V3 pattern: normalize file inputs from basic/advanced modes
const documentInput = normalizeFileInput(
params.fileUpload || params.fileReference || params.document,
{ single: true }
Expand Down
7 changes: 6 additions & 1 deletion apps/sim/blocks/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,11 @@ import { MemoryBlock } from '@/blocks/blocks/memory'
import { MicrosoftExcelBlock, MicrosoftExcelV2Block } from '@/blocks/blocks/microsoft_excel'
import { MicrosoftPlannerBlock } from '@/blocks/blocks/microsoft_planner'
import { MicrosoftTeamsBlock } from '@/blocks/blocks/microsoft_teams'
import { MistralParseBlock, MistralParseV2Block } from '@/blocks/blocks/mistral_parse'
import {
MistralParseBlock,
MistralParseV2Block,
MistralParseV3Block,
} from '@/blocks/blocks/mistral_parse'
import { MongoDBBlock } from '@/blocks/blocks/mongodb'
import { MySQLBlock } from '@/blocks/blocks/mysql'
import { Neo4jBlock } from '@/blocks/blocks/neo4j'
Expand Down Expand Up @@ -255,6 +259,7 @@ export const registry: Record<string, BlockConfig> = {
microsoft_teams: MicrosoftTeamsBlock,
mistral_parse: MistralParseBlock,
mistral_parse_v2: MistralParseV2Block,
mistral_parse_v3: MistralParseV3Block,
mongodb: MongoDBBlock,
mysql: MySQLBlock,
neo4j: Neo4jBlock,
Expand Down
4 changes: 2 additions & 2 deletions apps/sim/tools/mistral/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { mistralParserTool, mistralParserV2Tool } from '@/tools/mistral/parser'
import { mistralParserTool, mistralParserV2Tool, mistralParserV3Tool } from '@/tools/mistral/parser'

export { mistralParserTool, mistralParserV2Tool }
export { mistralParserTool, mistralParserV2Tool, mistralParserV3Tool }
136 changes: 73 additions & 63 deletions apps/sim/tools/mistral/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,74 +349,14 @@ export const mistralParserTool: ToolConfig<MistralParserInput, MistralParserOutp
},
}

const mistralParserV2Params = {
file: {
type: 'file',
required: true,
visibility: 'hidden',
description: 'File data from a previous block',
},
resultType: mistralParserTool.params.resultType,
includeImageBase64: mistralParserTool.params.includeImageBase64,
pages: mistralParserTool.params.pages,
imageLimit: mistralParserTool.params.imageLimit,
imageMinSize: mistralParserTool.params.imageMinSize,
apiKey: mistralParserTool.params.apiKey,
} satisfies ToolConfig['params']

export const mistralParserV2Tool: ToolConfig<MistralParserV2Input, MistralParserV2Output> = {
export const mistralParserV2Tool: ToolConfig<MistralParserInput, MistralParserV2Output> = {
id: 'mistral_parser_v2',
name: 'Mistral PDF Parser',
description: 'Parse PDF documents using Mistral OCR API',
version: '2.0.0',

params: mistralParserV2Params,
request: {
url: '/api/tools/mistral/parse',
method: 'POST',
headers: (params) => {
return {
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}
},
body: (params) => {
if (!params || typeof params !== 'object') {
throw new Error('Invalid parameters: Parameters must be provided as an object')
}
if (!params.apiKey || typeof params.apiKey !== 'string' || params.apiKey.trim() === '') {
throw new Error('Missing or invalid API key: A valid Mistral API key is required')
}

const file = params.file
if (!file || typeof file !== 'object') {
throw new Error('File input is required')
}

const requestBody: Record<string, unknown> = {
apiKey: params.apiKey,
resultType: params.resultType || 'markdown',
}

requestBody.file = file

if (params.pages) {
requestBody.pages = params.pages
}
if (params.includeImageBase64 !== undefined) {
requestBody.includeImageBase64 = params.includeImageBase64
}
if (params.imageLimit !== undefined) {
requestBody.imageLimit = params.imageLimit
}
if (params.imageMinSize !== undefined) {
requestBody.imageMinSize = params.imageMinSize
}

return requestBody
},
},
params: mistralParserTool.params,
request: mistralParserTool.request,

transformResponse: async (response: Response) => {
let ocrResult
Expand Down Expand Up @@ -543,3 +483,73 @@ export const mistralParserV2Tool: ToolConfig<MistralParserV2Input, MistralParser
},
},
}

/**
* V3 tool - Updated for new file handling pattern with UserFile normalization
* Used by MistralParseV3Block which uses fileUpload (basic) and fileReference (advanced) subblocks
*/
export const mistralParserV3Tool: ToolConfig<MistralParserV2Input, MistralParserV2Output> = {
...mistralParserV2Tool,
id: 'mistral_parser_v3',
version: '3.0.0',
params: {
file: {
type: 'file',
required: true,
visibility: 'hidden',
description: 'Normalized UserFile from file upload or file reference',
},
resultType: mistralParserTool.params.resultType,
includeImageBase64: mistralParserTool.params.includeImageBase64,
pages: mistralParserTool.params.pages,
imageLimit: mistralParserTool.params.imageLimit,
imageMinSize: mistralParserTool.params.imageMinSize,
apiKey: mistralParserTool.params.apiKey,
},
request: {
url: '/api/tools/mistral/parse',
method: 'POST',
headers: (params) => {
return {
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}
},
body: (params) => {
if (!params || typeof params !== 'object') {
throw new Error('Invalid parameters: Parameters must be provided as an object')
}
if (!params.apiKey || typeof params.apiKey !== 'string' || params.apiKey.trim() === '') {
throw new Error('Missing or invalid API key: A valid Mistral API key is required')
}

// V3 expects normalized UserFile object via `file` param
const file = params.file
if (!file || typeof file !== 'object') {
throw new Error('File input is required: provide a file upload or file reference')
}

const requestBody: Record<string, unknown> = {
apiKey: params.apiKey,
resultType: params.resultType || 'markdown',
file: file,
}

if (params.pages) {
requestBody.pages = params.pages
}
if (params.includeImageBase64 !== undefined) {
requestBody.includeImageBase64 = params.includeImageBase64
}
if (params.imageLimit !== undefined) {
requestBody.imageLimit = params.imageLimit
}
if (params.imageMinSize !== undefined) {
requestBody.imageMinSize = params.imageMinSize
}

return requestBody
},
},
}
3 changes: 2 additions & 1 deletion apps/sim/tools/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1093,7 +1093,7 @@ import {
microsoftTeamsWriteChannelTool,
microsoftTeamsWriteChatTool,
} from '@/tools/microsoft_teams'
import { mistralParserTool, mistralParserV2Tool } from '@/tools/mistral'
import { mistralParserTool, mistralParserV2Tool, mistralParserV3Tool } from '@/tools/mistral'
import {
mongodbDeleteTool,
mongodbExecuteTool,
Expand Down Expand Up @@ -2684,6 +2684,7 @@ export const tools: Record<string, ToolConfig> = {
apollo_email_accounts: apolloEmailAccountsTool,
mistral_parser: mistralParserTool,
mistral_parser_v2: mistralParserV2Tool,
mistral_parser_v3: mistralParserV3Tool,
reducto_parser: reductoParserTool,
reducto_parser_v2: reductoParserV2Tool,
textract_parser: textractParserTool,
Expand Down