Skip to content
42 changes: 26 additions & 16 deletions packages/components/nodes/agentflow/Agent/Agent.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import crypto from 'crypto'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: import { randomBytes } from 'crypto'

import { BaseChatModel } from '@langchain/core/language_models/chat_models'
import {
ICommonObject,
Expand Down Expand Up @@ -65,6 +66,27 @@ interface ISimpliefiedTool {
}
}

/**
* 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()}_${crypto.randomBytes(3).toString('hex')}`
}

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

class Agent_Agentflow implements INode {
label: string
name: string
Expand Down Expand Up @@ -757,10 +779,7 @@ class Agent_Agentflow implements INode {
...nodeData,
inputs: {
...nodeData.inputs,
name: storeName
.toLowerCase()
.replace(/ /g, '_')
.replace(/[^a-z0-9_-]/g, ''),
name: sanitizeToolName(storeName),
description: knowledgeBase.docStoreDescription,
retriever: docStoreVectorInstance,
returnSourceDocuments: knowledgeBase.returnSourceDocuments
Expand All @@ -777,10 +796,7 @@ class Agent_Agentflow implements INode {
const componentNode = options.componentNodes['retrieverTool']

availableTools.push({
name: storeName
.toLowerCase()
.replace(/ /g, '_')
.replace(/[^a-z0-9_-]/g, ''),
name: sanitizeToolName(storeName),
description: knowledgeBase.docStoreDescription,
schema: jsonSchema,
toolNode: {
Expand Down Expand Up @@ -838,10 +854,7 @@ class Agent_Agentflow implements INode {
...nodeData,
inputs: {
...nodeData.inputs,
name: knowledgeName
.toLowerCase()
.replace(/ /g, '_')
.replace(/[^a-z0-9_-]/g, ''),
name: sanitizeToolName(knowledgeName),
description: knowledgeBase.knowledgeDescription,
retriever: vectorStoreInstance,
returnSourceDocuments: knowledgeBase.returnSourceDocuments
Expand All @@ -858,10 +871,7 @@ class Agent_Agentflow implements INode {
const componentNode = options.componentNodes['retrieverTool']

availableTools.push({
name: knowledgeName
.toLowerCase()
.replace(/ /g, '_')
.replace(/[^a-z0-9_-]/g, ''),
name: sanitizeToolName(knowledgeName),
description: knowledgeBase.knowledgeDescription,
schema: jsonSchema,
toolNode: {
Expand Down