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
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '../../../src/Interface'
import axios, { AxiosRequestConfig } from 'axios'
import { getCredentialData, getCredentialParam, processTemplateVariables } from '../../../src/utils'
import JSON5 from 'json5'
import { DataSource } from 'typeorm'
import { BaseMessageLike } from '@langchain/core/messages'
import { updateFlowState } from '../utils'
Expand Down Expand Up @@ -167,9 +168,7 @@ class ExecuteFlow_Agentflow implements INode {
let overrideConfig = nodeData.inputs?.executeFlowOverrideConfig
if (typeof overrideConfig === 'string' && overrideConfig.startsWith('{') && overrideConfig.endsWith('}')) {
try {
// Handle escaped square brackets and other common escape sequences
const unescapedConfig = overrideConfig.replace(/\\(\[|\])/g, '$1')
overrideConfig = JSON.parse(unescapedConfig)
overrideConfig = JSON5.parse(overrideConfig)
} catch (parseError) {
throw new Error(`Invalid JSON in executeFlowOverrideConfig: ${parseError.message}`)
}
Expand Down
30 changes: 5 additions & 25 deletions packages/components/nodes/agentflow/HTTP/HTTP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import FormData from 'form-data'
import * as querystring from 'querystring'
import { getCredentialData, getCredentialParam } from '../../../src/utils'
import { secureAxiosRequest } from '../../../src/httpSecurity'
import JSON5 from 'json5'

class HTTP_Agentflow implements INode {
label: string
Expand All @@ -19,34 +20,13 @@ class HTTP_Agentflow implements INode {
credential: INodeParams
inputs: INodeParams[]

private sanitizeJsonString(jsonString: string): string {
// Remove common problematic escape sequences that are not valid JSON
let sanitized = jsonString
// Remove escaped square brackets (not valid JSON)
.replace(/\\(\[|\])/g, '$1')
// Fix unquoted string values in JSON (simple case)
.replace(/:\s*([a-zA-Z][a-zA-Z0-9]*)\s*([,}])/g, ': "$1"$2')
// Fix trailing commas
.replace(/,(\s*[}\]])/g, '$1')

return sanitized
}

private parseJsonBody(body: string): any {
try {
// First try to parse as-is
return JSON.parse(body)
return JSON5.parse(body)
} catch (error) {
try {
// If that fails, try to sanitize and parse
const sanitized = this.sanitizeJsonString(body)
return JSON.parse(sanitized)
} catch (sanitizeError) {
// If sanitization also fails, throw the original error with helpful message
throw new Error(
`Invalid JSON format in body. Original error: ${error.message}. Please ensure your JSON is properly formatted with quoted strings and valid escape sequences.`
)
}
throw new Error(
`Invalid JSON format in body. Original error: ${error.message}. Please ensure your JSON is properly formatted with quoted strings and valid escape sequences.`
)
}
}

Expand Down
5 changes: 3 additions & 2 deletions packages/components/nodes/agentflow/Iteration/Iteration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import JSON5 from 'json5'

class Iteration_Agentflow implements INode {
label: string
Expand Down Expand Up @@ -41,10 +42,10 @@ class Iteration_Agentflow implements INode {
// Helper function to clean JSON strings with redundant backslashes
const safeParseJson = (str: string): string => {
try {
return JSON.parse(str)
return JSON5.parse(str)
} catch {
// Try parsing after cleaning
return JSON.parse(str.replace(/\\(["'[\]{}])/g, '$1'))
return JSON5.parse(str.replace(/\\(["'[\]{}])/g, '$1'))
}
}

Expand Down
3 changes: 2 additions & 1 deletion packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { MCPToolkit } from '../core'
import { getVars, prepareSandboxVars } from '../../../../src/utils'
import { DataSource } from 'typeorm'
import hash from 'object-hash'
import JSON5 from 'json5'

const mcpServerConfig = `{
"command": "npx",
Expand Down Expand Up @@ -261,7 +262,7 @@ function substituteVariablesInString(str: string, sandbox: any): string {

function convertToValidJSONString(inputString: string) {
try {
const jsObject = Function('return ' + inputString)()
const jsObject = JSON5.parse(inputString)
return JSON.stringify(jsObject, null, 2)
} catch (error) {
console.error('Error converting to JSON:', error)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, stripHTMLFromToolInput } from '../../../src/utils'
import { desc, RequestParameters, RequestsDeleteTool } from './core'
import JSON5 from 'json5'

const codeExample = `{
"id": {
Expand Down Expand Up @@ -130,7 +131,7 @@ class RequestsDelete_Tools implements INode {
if (queryParamsSchema) obj.queryParamsSchema = queryParamsSchema
if (maxOutputLength) obj.maxOutputLength = parseInt(maxOutputLength, 10)
if (headers) {
const parsedHeaders = typeof headers === 'object' ? headers : JSON.parse(stripHTMLFromToolInput(headers))
const parsedHeaders = typeof headers === 'object' ? headers : JSON5.parse(stripHTMLFromToolInput(headers))
obj.headers = parsedHeaders
}

Expand Down
5 changes: 3 additions & 2 deletions packages/components/nodes/tools/RequestsDelete/core.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { z } from 'zod'
import { DynamicStructuredTool } from '../OpenAPIToolkit/core'
import { secureFetch } from '../../../src/httpSecurity'
import JSON5 from 'json5'

export const desc = `Use this when you need to execute a DELETE request to remove data from a website.`

Expand All @@ -22,7 +23,7 @@ const createRequestsDeleteSchema = (queryParamsSchema?: string) => {
// If queryParamsSchema is provided, parse it and add dynamic query params
if (queryParamsSchema) {
try {
const parsedSchema = JSON.parse(queryParamsSchema)
const parsedSchema = JSON5.parse(queryParamsSchema)
const queryParamsObject: Record<string, z.ZodTypeAny> = {}

Object.entries(parsedSchema).forEach(([key, config]: [string, any]) => {
Expand Down Expand Up @@ -108,7 +109,7 @@ export class RequestsDeleteTool extends DynamicStructuredTool {

if (this.queryParamsSchema && params.queryParams && Object.keys(params.queryParams).length > 0) {
try {
const parsedSchema = JSON.parse(this.queryParamsSchema)
const parsedSchema = JSON5.parse(this.queryParamsSchema)
const pathParams: Array<{ key: string; value: string }> = []

Object.entries(params.queryParams).forEach(([key, value]) => {
Expand Down
3 changes: 2 additions & 1 deletion packages/components/nodes/tools/RequestsGet/RequestsGet.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, stripHTMLFromToolInput } from '../../../src/utils'
import { desc, RequestParameters, RequestsGetTool } from './core'
import JSON5 from 'json5'

const codeExample = `{
"id": {
Expand Down Expand Up @@ -130,7 +131,7 @@ class RequestsGet_Tools implements INode {
if (queryParamsSchema) obj.queryParamsSchema = queryParamsSchema
if (maxOutputLength) obj.maxOutputLength = parseInt(maxOutputLength, 10)
if (headers) {
const parsedHeaders = typeof headers === 'object' ? headers : JSON.parse(stripHTMLFromToolInput(headers))
const parsedHeaders = typeof headers === 'object' ? headers : JSON5.parse(stripHTMLFromToolInput(headers))
obj.headers = parsedHeaders
}

Expand Down
5 changes: 3 additions & 2 deletions packages/components/nodes/tools/RequestsGet/core.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { z } from 'zod'
import { DynamicStructuredTool } from '../OpenAPIToolkit/core'
import { secureFetch } from '../../../src/httpSecurity'
import JSON5 from 'json5'

export const desc = `Use this when you need to execute a GET request to get data from a website.`

Expand All @@ -22,7 +23,7 @@ const createRequestsGetSchema = (queryParamsSchema?: string) => {
// If queryParamsSchema is provided, parse it and add dynamic query params
if (queryParamsSchema) {
try {
const parsedSchema = JSON.parse(queryParamsSchema)
const parsedSchema = JSON5.parse(queryParamsSchema)
const queryParamsObject: Record<string, z.ZodTypeAny> = {}

Object.entries(parsedSchema).forEach(([key, config]: [string, any]) => {
Expand Down Expand Up @@ -108,7 +109,7 @@ export class RequestsGetTool extends DynamicStructuredTool {

if (this.queryParamsSchema && params.queryParams && Object.keys(params.queryParams).length > 0) {
try {
const parsedSchema = JSON.parse(this.queryParamsSchema)
const parsedSchema = JSON5.parse(this.queryParamsSchema)
const pathParams: Array<{ key: string; value: string }> = []

Object.entries(params.queryParams).forEach(([key, value]) => {
Expand Down
5 changes: 3 additions & 2 deletions packages/components/nodes/tools/RequestsPost/RequestsPost.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, stripHTMLFromToolInput } from '../../../src/utils'
import { RequestParameters, desc, RequestsPostTool } from './core'
import JSON5 from 'json5'

const codeExample = `{
"name": {
Expand Down Expand Up @@ -140,11 +141,11 @@ class RequestsPost_Tools implements INode {
if (bodySchema) obj.bodySchema = stripHTMLFromToolInput(bodySchema)
if (maxOutputLength) obj.maxOutputLength = parseInt(maxOutputLength, 10)
if (headers) {
const parsedHeaders = typeof headers === 'object' ? headers : JSON.parse(stripHTMLFromToolInput(headers))
const parsedHeaders = typeof headers === 'object' ? headers : JSON5.parse(stripHTMLFromToolInput(headers))
obj.headers = parsedHeaders
}
if (body) {
const parsedBody = typeof body === 'object' ? body : JSON.parse(body)
const parsedBody = typeof body === 'object' ? body : JSON5.parse(body)
obj.body = parsedBody
}

Expand Down
3 changes: 2 additions & 1 deletion packages/components/nodes/tools/RequestsPost/core.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { z } from 'zod'
import { DynamicStructuredTool } from '../OpenAPIToolkit/core'
import { secureFetch } from '../../../src/httpSecurity'
import JSON5 from 'json5'

export const desc = `Use this when you want to execute a POST request to create or update a resource.`

Expand All @@ -27,7 +28,7 @@ const createRequestsPostSchema = (bodySchema?: string) => {
// If bodySchema is provided, parse it and add dynamic body params
if (bodySchema) {
try {
const parsedSchema = JSON.parse(bodySchema)
const parsedSchema = JSON5.parse(bodySchema)
const bodyParamsObject: Record<string, z.ZodTypeAny> = {}

Object.entries(parsedSchema).forEach(([key, config]: [string, any]) => {
Expand Down
5 changes: 3 additions & 2 deletions packages/components/nodes/tools/RequestsPut/RequestsPut.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, stripHTMLFromToolInput } from '../../../src/utils'
import { RequestParameters, desc, RequestsPutTool } from './core'
import JSON5 from 'json5'

const codeExample = `{
"name": {
Expand Down Expand Up @@ -140,11 +141,11 @@ class RequestsPut_Tools implements INode {
if (bodySchema) obj.bodySchema = stripHTMLFromToolInput(bodySchema)
if (maxOutputLength) obj.maxOutputLength = parseInt(maxOutputLength, 10)
if (headers) {
const parsedHeaders = typeof headers === 'object' ? headers : JSON.parse(stripHTMLFromToolInput(headers))
const parsedHeaders = typeof headers === 'object' ? headers : JSON5.parse(stripHTMLFromToolInput(headers))
obj.headers = parsedHeaders
}
if (body) {
const parsedBody = typeof body === 'object' ? body : JSON.parse(body)
const parsedBody = typeof body === 'object' ? body : JSON5.parse(body)
obj.body = parsedBody
}

Expand Down
3 changes: 2 additions & 1 deletion packages/components/nodes/tools/RequestsPut/core.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { z } from 'zod'
import { DynamicStructuredTool } from '../OpenAPIToolkit/core'
import { secureFetch } from '../../../src/httpSecurity'
import JSON5 from 'json5'

export const desc = `Use this when you want to execute a PUT request to update or replace a resource.`

Expand All @@ -27,7 +28,7 @@ const createRequestsPutSchema = (bodySchema?: string) => {
// If bodySchema is provided, parse it and add dynamic body params
if (bodySchema) {
try {
const parsedSchema = JSON.parse(bodySchema)
const parsedSchema = JSON5.parse(bodySchema)
const bodyParamsObject: Record<string, z.ZodTypeAny> = {}

Object.entries(parsedSchema).forEach(([key, config]: [string, any]) => {
Expand Down