diff --git a/packages/twenty-server/src/engine/api/mcp/services/mcp-protocol.service.ts b/packages/twenty-server/src/engine/api/mcp/services/mcp-protocol.service.ts index c83cbe94c9e..af25f2ff0dd 100644 --- a/packages/twenty-server/src/engine/api/mcp/services/mcp-protocol.service.ts +++ b/packages/twenty-server/src/engine/api/mcp/services/mcp-protocol.service.ts @@ -118,6 +118,7 @@ export class McpProtocolService { const preloadedTools = await this.toolRegistry.getToolsByName( COMMON_PRELOAD_TOOLS, toolContext, + { includeLoadingMessage: false }, ); return { diff --git a/packages/twenty-server/src/engine/core-modules/tool-provider/interfaces/tool-retrieval-options.type.ts b/packages/twenty-server/src/engine/core-modules/tool-provider/interfaces/tool-retrieval-options.type.ts index ef8b3d071f8..208cbaf9594 100644 --- a/packages/twenty-server/src/engine/core-modules/tool-provider/interfaces/tool-retrieval-options.type.ts +++ b/packages/twenty-server/src/engine/core-modules/tool-provider/interfaces/tool-retrieval-options.type.ts @@ -4,4 +4,5 @@ export type ToolRetrievalOptions = { categories?: ToolCategory[]; excludeTools?: string[]; wrapWithErrorContext?: boolean; + includeLoadingMessage?: boolean; }; diff --git a/packages/twenty-server/src/engine/core-modules/tool-provider/services/tool-executor.service.ts b/packages/twenty-server/src/engine/core-modules/tool-provider/services/tool-executor.service.ts index d04feb163d4..32b6992a75a 100644 --- a/packages/twenty-server/src/engine/core-modules/tool-provider/services/tool-executor.service.ts +++ b/packages/twenty-server/src/engine/core-modules/tool-provider/services/tool-executor.service.ts @@ -33,7 +33,6 @@ import { type ToolDescriptor } from 'src/engine/core-modules/tool-provider/types import { type ToolExecutionRef } from 'src/engine/core-modules/tool-provider/types/tool-execution-ref.type'; import { type ToolIndexEntry } from 'src/engine/core-modules/tool-provider/types/tool-index-entry.type'; import { type ToolOutput } from 'src/engine/core-modules/tool/types/tool-output.type'; -import { stripLoadingMessage } from 'src/engine/core-modules/tool/utils/wrap-tool-for-execution.util'; import { UserEntity } from 'src/engine/core-modules/user/user.entity'; import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; @@ -77,24 +76,24 @@ export class ToolExecutorService { async dispatch( descriptor: ToolIndexEntry | ToolDescriptor, - args: Record, + args: Record | undefined, context: ToolProviderContext, ): Promise { - const cleanArgs = stripLoadingMessage(args); + const safeArgs = args ?? {}; switch (descriptor.executionRef.kind) { case 'database_crud': return this.dispatchDatabaseCrud( descriptor.executionRef, - cleanArgs, + safeArgs, context, ); case 'static': - return this.dispatchStaticTool(descriptor, cleanArgs, context); + return this.dispatchStaticTool(descriptor, safeArgs, context); case 'logic_function': return this.dispatchLogicFunction( descriptor.executionRef, - cleanArgs, + safeArgs, context, ); } diff --git a/packages/twenty-server/src/engine/core-modules/tool-provider/services/tool-registry.service.ts b/packages/twenty-server/src/engine/core-modules/tool-provider/services/tool-registry.service.ts index fae767a5f40..e1b7da4fe2a 100644 --- a/packages/twenty-server/src/engine/core-modules/tool-provider/services/tool-registry.service.ts +++ b/packages/twenty-server/src/engine/core-modules/tool-provider/services/tool-registry.service.ts @@ -17,7 +17,10 @@ import { type ToolDescriptor } from 'src/engine/core-modules/tool-provider/types import { type ToolIndexEntry } from 'src/engine/core-modules/tool-provider/types/tool-index-entry.type'; import { wrapWithErrorHandler } from 'src/engine/core-modules/tool-provider/utils/tool-error.util'; import { type ToolOutput } from 'src/engine/core-modules/tool/types/tool-output.type'; -import { wrapJsonSchemaForExecution } from 'src/engine/core-modules/tool/utils/wrap-tool-for-execution.util'; +import { + stripLoadingMessage, + wrapJsonSchemaForExecution, +} from 'src/engine/core-modules/tool/utils/wrap-tool-for-execution.util'; import { type RolePermissionConfig } from 'src/engine/twenty-orm/types/role-permission-config'; @Injectable() @@ -104,23 +107,37 @@ export class ToolRegistryService { hydrateToolSet( descriptors: ToolDescriptor[], context: ToolProviderContext, - options?: { wrapWithErrorContext?: boolean }, + options?: { + wrapWithErrorContext?: boolean; + includeLoadingMessage?: boolean; + }, ): ToolSet { const toolSet: ToolSet = {}; + const includeLoadingMessage = options?.includeLoadingMessage ?? true; for (const descriptor of descriptors) { - const schemaWithLoading = wrapJsonSchemaForExecution( - descriptor.inputSchema as Record, - ); + const baseSchema = descriptor.inputSchema as Record; + const schema = includeLoadingMessage + ? wrapJsonSchemaForExecution(baseSchema) + : baseSchema; const executeFn = async ( args: Record, - ): Promise => - this.toolExecutorService.dispatch(descriptor, args, context); + ): Promise => { + const cleanArgs = includeLoadingMessage + ? stripLoadingMessage(args ?? {}) + : (args ?? {}); + + return this.toolExecutorService.dispatch( + descriptor, + cleanArgs, + context, + ); + }; toolSet[descriptor.name] = { description: descriptor.description, - inputSchema: jsonSchema(schemaWithLoading), + inputSchema: jsonSchema(schema), execute: options?.wrapWithErrorContext ? wrapWithErrorHandler(descriptor.name, executeFn) : executeFn, @@ -148,6 +165,7 @@ export class ToolRegistryService { async getToolsByName( names: string[], context: ToolContext, + options?: { includeLoadingMessage?: boolean }, ): Promise { const fullContext = this.buildContextFromToolContext(context); @@ -164,7 +182,9 @@ export class ToolRegistryService { inputSchema: schemas.get(entry.name)!, })); - return this.hydrateToolSet(descriptors, fullContext); + return this.hydrateToolSet(descriptors, fullContext, { + includeLoadingMessage: options?.includeLoadingMessage, + }); } async getToolInfo( @@ -207,7 +227,7 @@ export class ToolRegistryService { async resolveAndExecute( toolName: string, - args: Record, + args: Record | undefined, context: ToolContext, _options: ToolExecutionOptions, ): Promise { @@ -246,7 +266,12 @@ export class ToolRegistryService { context: ToolProviderContext, options: ToolRetrievalOptions = {}, ): Promise { - const { categories, excludeTools, wrapWithErrorContext } = options; + const { + categories, + excludeTools, + wrapWithErrorContext, + includeLoadingMessage, + } = options; const categorySet = categories ? new Set(categories) : undefined; const results = await Promise.all( @@ -279,6 +304,7 @@ export class ToolRegistryService { const toolSet = this.hydrateToolSet(filteredDescriptors, context, { wrapWithErrorContext, + includeLoadingMessage, }); if (categories?.includes(ToolCategory.NATIVE_MODEL)) { diff --git a/packages/twenty-server/src/engine/core-modules/tool-provider/tools/execute-tool.tool.ts b/packages/twenty-server/src/engine/core-modules/tool-provider/tools/execute-tool.tool.ts index 552af38ae55..f5335c8a6cf 100644 --- a/packages/twenty-server/src/engine/core-modules/tool-provider/tools/execute-tool.tool.ts +++ b/packages/twenty-server/src/engine/core-modules/tool-provider/tools/execute-tool.tool.ts @@ -54,7 +54,7 @@ export const createExecuteToolTool = ( parameters: ExecuteToolInput, options: ToolExecutionOptions, ): Promise => { - const { toolName, arguments: args } = parameters; + const { toolName, arguments: args = {} } = parameters; if (excludeTools?.has(toolName)) { return {