Skip to content

Commit 7dc4851

Browse files
authored
fix(tool-input): allow multiple instances of workflow block or kb tools as agent tools (#2495)
* fix(tool-input): allow multiple instances of workflow block or kb tools as agent tools * ack PR comments
1 parent 93fe687 commit 7dc4851

File tree

6 files changed

+62
-18
lines changed

6 files changed

+62
-18
lines changed

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tool-input/tool-input.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,11 @@ export function ToolInput({
982982
if (hasMultipleOperations(blockType)) {
983983
return false
984984
}
985+
// Allow multiple instances for workflow and knowledge blocks
986+
// Each instance can target a different workflow/knowledge base
987+
if (blockType === 'workflow' || blockType === 'knowledge') {
988+
return false
989+
}
985990
return selectedTools.some((tool) => tool.toolId === toolId)
986991
}
987992

apps/sim/components/emcn/components/popover/popover.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -720,8 +720,10 @@ const PopoverSearch = React.forwardRef<HTMLDivElement, PopoverSearchProps>(
720720
}
721721

722722
React.useEffect(() => {
723+
setSearchQuery('')
724+
onValueChange?.('')
723725
inputRef.current?.focus()
724-
}, [])
726+
}, [setSearchQuery, onValueChange])
725727

726728
return (
727729
<div ref={ref} className={cn('flex items-center px-[8px] py-[6px]', className)} {...props}>

apps/sim/providers/utils.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,8 +479,16 @@ export async function transformBlockTool(
479479

480480
const llmSchema = await createLLMToolSchema(toolConfig, userProvidedParams)
481481

482+
// Create unique tool ID by appending resource ID for multi-instance tools
483+
let uniqueToolId = toolConfig.id
484+
if (toolId === 'workflow_executor' && userProvidedParams.workflowId) {
485+
uniqueToolId = `${toolConfig.id}_${userProvidedParams.workflowId}`
486+
} else if (toolId.startsWith('knowledge_') && userProvidedParams.knowledgeBaseId) {
487+
uniqueToolId = `${toolConfig.id}_${userProvidedParams.knowledgeBaseId}`
488+
}
489+
482490
return {
483-
id: toolConfig.id,
491+
id: uniqueToolId,
484492
name: toolConfig.name,
485493
description: toolConfig.description,
486494
params: userProvidedParams,

apps/sim/tools/index.ts

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,26 @@ import {
1616

1717
const logger = createLogger('Tools')
1818

19+
/**
20+
* Normalizes a tool ID by stripping resource ID suffix (UUID).
21+
* Workflow tools: 'workflow_executor_<uuid>' -> 'workflow_executor'
22+
* Knowledge tools: 'knowledge_search_<uuid>' -> 'knowledge_search'
23+
*/
24+
function normalizeToolId(toolId: string): string {
25+
// Check for workflow_executor_<uuid> pattern
26+
if (toolId.startsWith('workflow_executor_') && toolId.length > 'workflow_executor_'.length) {
27+
return 'workflow_executor'
28+
}
29+
// Check for knowledge_<operation>_<uuid> pattern
30+
const knowledgeOps = ['knowledge_search', 'knowledge_upload_chunk', 'knowledge_create_document']
31+
for (const op of knowledgeOps) {
32+
if (toolId.startsWith(`${op}_`) && toolId.length > op.length + 1) {
33+
return op
34+
}
35+
}
36+
return toolId
37+
}
38+
1939
/**
2040
* Maximum request body size in bytes before we warn/error about size limits.
2141
* Next.js 16 has a default middleware/proxy body limit of 10MB.
@@ -186,20 +206,29 @@ export async function executeTool(
186206
try {
187207
let tool: ToolConfig | undefined
188208

209+
// Normalize tool ID to strip resource suffixes (e.g., workflow_executor_<uuid> -> workflow_executor)
210+
const normalizedToolId = normalizeToolId(toolId)
211+
189212
// If it's a custom tool, use the async version with workflowId
190-
if (toolId.startsWith('custom_')) {
213+
if (normalizedToolId.startsWith('custom_')) {
191214
const workflowId = params._context?.workflowId
192-
tool = await getToolAsync(toolId, workflowId)
215+
tool = await getToolAsync(normalizedToolId, workflowId)
193216
if (!tool) {
194-
logger.error(`[${requestId}] Custom tool not found: ${toolId}`)
217+
logger.error(`[${requestId}] Custom tool not found: ${normalizedToolId}`)
195218
}
196-
} else if (toolId.startsWith('mcp-')) {
197-
return await executeMcpTool(toolId, params, executionContext, requestId, startTimeISO)
219+
} else if (normalizedToolId.startsWith('mcp-')) {
220+
return await executeMcpTool(
221+
normalizedToolId,
222+
params,
223+
executionContext,
224+
requestId,
225+
startTimeISO
226+
)
198227
} else {
199228
// For built-in tools, use the synchronous version
200-
tool = getTool(toolId)
229+
tool = getTool(normalizedToolId)
201230
if (!tool) {
202-
logger.error(`[${requestId}] Built-in tool not found: ${toolId}`)
231+
logger.error(`[${requestId}] Built-in tool not found: ${normalizedToolId}`)
203232
}
204233
}
205234

bun.lock

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
"drizzle-kit": "^0.31.4",
6767
"husky": "9.1.7",
6868
"lint-staged": "16.0.0",
69-
"turbo": "2.6.3"
69+
"turbo": "2.7.0"
7070
},
7171
"lint-staged": {
7272
"*.{js,jsx,ts,tsx,json,css,scss}": [

0 commit comments

Comments
 (0)