Repository: FlowiseAI/Flowise
File: packages/components/nodes/agentflow/Agent/Agent.ts (TypeScript)

Code before:

interface ISimpliefiedTool {
    name: string
    description: string
    schema: any
    toolNode: {
        label: string
        name: string
    }
}

/**
 * Sanitizes a string to be used as a tool name.
 * Restricts to ASCII characters [a-z0-9_-] for LLM API compatibility (OpenAI, Anthropic, Gemini).
 * Non-ASCII titles (Korean, Chinese, Japanese, etc.) will use auto-generated fallback names.
 * This prevents 'Invalid tools[0].function.name: empty string' errors.
 */
const sanitizeToolName = (name: string): string => {
    const sanitized = name
        .toLowerCase()
        .replace(/ /g, '_')
        .replace(/[^a-z0-9_-]/g, '') // ASCII only for LLM API compatibility
    
    // If the result is empty (e.g., non-ASCII only input), generate a unique fallback name
    if (!sanitized) {
        return `tool_${crypto.randomBytes(8).toString('hex')}`
    }
    
    // Enforce 64 character limit common for tool names
    return sanitized.slice(0, 64)
}

class Agent_Agentflow implements INode {
    label: string
    name: string
    version: number
    description: string
    type: string
    icon: string
    category: string
    color: string
    baseClasses: string[]
    documentation?: string
    credential: INodeParams
    inputs: INodeParams[]

    constructor() {
        this.label = 'Agent'
        this.name = 'agentAgentflow'
        this.version = 3.2
        this.type = 'Agent'

Review comment (security):
I noticed you already used `Math.random()` below. I think it should be enough for the random name.
```return `tool_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;```
This can avoid importing the crypto library just for generating a random name, since it doesn't require cryptographic security.

It seems that Gemini proposed to use `crypto.randomBytes`.  I'm open to either option.

Code after:

interface ISimpliefiedTool {
    name: string
    description: string
    schema: any
    toolNode: {
        label: string
        name: string
    }
}

/**
 * Sanitizes a string to be used as a tool name.
 * Restricts to ASCII characters [a-z0-9_-] for LLM API compatibility (OpenAI, Anthropic, Gemini).
 * Non-ASCII titles (Korean, Chinese, Japanese, etc.) will use auto-generated fallback names.
 * This prevents 'Invalid tools[0].function.name: empty string' errors.
 */
const sanitizeToolName = (name: string): string => {
    const sanitized = name
        .toLowerCase()
        .replace(/ /g, '_')
        .replace(/[^a-z0-9_-]/g, '') // ASCII only for LLM API compatibility

    // If the result is empty (e.g., non-ASCII only input), generate a unique fallback name
    if (!sanitized) {
        return `tool_${Date.now()}_${randomBytes(4).toString('hex').slice(0, 5)}`
    }

    // Enforce 64 character limit common for tool names
    return sanitized.slice(0, 64)
}

class Agent_Agentflow implements INode {
    label: string
    name: string
    version: number
    description: string
    type: string
    icon: string
    category: string
    color: string
    baseClasses: string[]
    documentation?: string
    credential: INodeParams
    inputs: INodeParams[]

    constructor() {
        this.label = 'Agent'
        this.name = 'agentAgentflow'
        this.version = 3.2
        this.type = 'Agent'