Support define is tool logic function (#17926)

- supports isTool and timeout settings in defineLogicFunction in apps
and in setting tabs definition
- compute for all toolInputSchema for logic funciton, in settings and in
code steps

<img width="991" height="802" alt="image"
src="https://github.com/user-attachments/assets/05dc1221-cac9-45a3-87b0-3b13161446fd"
/>
This commit is contained in:
martmull
2026-02-16 10:43:29 +01:00
committed by GitHub
parent f694bb99b3
commit da064d5e88
138 changed files with 4839 additions and 367 deletions
@@ -1,5 +1,7 @@
import { Test, type TestingModule } from '@nestjs/testing';
import { DEFAULT_TOOL_INPUT_SCHEMA } from 'twenty-shared/logic-function';
import { MCP_SERVER_METADATA } from 'src/engine/api/mcp/constants/mcp.const';
import { McpCoreController } from 'src/engine/api/mcp/controllers/mcp-core.controller';
import { type JsonRpc } from 'src/engine/api/mcp/dtos/json-rpc';
@@ -152,7 +154,7 @@ describe('McpCoreController', () => {
{
name: 'testTool',
description: 'A test tool',
inputSchema: { type: 'object', properties: {} },
inputSchema: DEFAULT_TOOL_INPUT_SCHEMA,
},
],
},
@@ -3,6 +3,8 @@ import { Test, type TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { jsonSchema } from 'ai';
import { type JSONSchema7 } from 'json-schema';
import { DEFAULT_TOOL_INPUT_SCHEMA } from 'twenty-shared/logic-function';
import { MCP_SERVER_METADATA } from 'src/engine/api/mcp/constants/mcp.const';
import { type JsonRpc } from 'src/engine/api/mcp/dtos/json-rpc';
@@ -264,7 +266,7 @@ describe('McpProtocolService', () => {
const mockTool = {
description: 'Test tool',
inputSchema: jsonSchema({ type: 'object', properties: {} }),
inputSchema: jsonSchema(DEFAULT_TOOL_INPUT_SCHEMA as JSONSchema7),
execute: jest.fn().mockResolvedValue({ result: 'success' }),
};
@@ -319,7 +321,7 @@ describe('McpProtocolService', () => {
const mockTool = {
description: 'Test tool',
inputSchema: jsonSchema({ type: 'object', properties: {} }),
inputSchema: jsonSchema(DEFAULT_TOOL_INPUT_SCHEMA as JSONSchema7),
execute: jest.fn().mockResolvedValue({ result: 'success' }),
};
@@ -375,7 +377,7 @@ describe('McpProtocolService', () => {
const mockToolsMap = {
testTool: {
description: 'Test tool',
inputSchema: jsonSchema({ type: 'object', properties: {} }),
inputSchema: jsonSchema(DEFAULT_TOOL_INPUT_SCHEMA as JSONSchema7),
},
};
@@ -393,7 +395,7 @@ describe('McpProtocolService', () => {
{
name: 'testTool',
description: 'Test tool',
inputSchema: { type: 'object', properties: {} },
inputSchema: DEFAULT_TOOL_INPUT_SCHEMA,
},
],
}),
@@ -28,7 +28,7 @@ export const fromLogicFunctionManifestToUniversalFlatLogicFunction = ({
builtHandlerPath: logicFunctionManifest.builtHandlerPath,
handlerName: logicFunctionManifest.handlerName,
checksum: logicFunctionManifest.builtHandlerChecksum,
toolInputSchema: logicFunctionManifest.toolInputSchema ?? null,
toolInputSchema: logicFunctionManifest.toolInputSchema,
isTool: logicFunctionManifest.isTool ?? false,
cronTriggerSettings: logicFunctionManifest.cronTriggerSettings ?? null,
databaseEventTriggerSettings:
@@ -1,4 +0,0 @@
export const SEED_LOGIC_FUNCTION_INPUT_SCHEMA = {
a: null,
b: null,
};
@@ -1,6 +1,7 @@
import { Injectable } from '@nestjs/common';
import { isDefined } from 'twenty-shared/utils';
import { DEFAULT_TOOL_INPUT_SCHEMA } from 'twenty-shared/logic-function';
import {
type GenerateDescriptorOptions,
@@ -68,10 +69,9 @@ export class LogicFunctionToolProvider implements ToolProvider {
if (includeSchemas) {
// Logic functions already store JSON Schema -- use it directly
const inputSchema = (logicFunction.toolInputSchema as object) ?? {
type: 'object',
properties: {},
};
const inputSchema =
(logicFunction.toolInputSchema as object) ??
DEFAULT_TOOL_INPUT_SCHEMA;
descriptors.push({ ...base, inputSchema });
} else {
@@ -1,7 +0,0 @@
export const DEFAULT_TOOL_INPUT_SCHEMA = {
type: 'object',
properties: {
a: { type: 'string' },
b: { type: 'number' },
},
};
@@ -18,6 +18,8 @@ import {
HttpRouteTriggerSettings,
} from 'twenty-shared/application';
import type { InputJsonSchema } from 'twenty-shared/logic-function';
import type { JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
@@ -52,7 +54,7 @@ export class CreateLogicFunction {
@Field(() => graphqlTypeJson, { nullable: false })
@IsObject()
toolInputSchema: object;
toolInputSchema: InputJsonSchema;
@IsBoolean()
@Field({ nullable: true })
@@ -22,6 +22,8 @@ import {
HttpRouteTriggerSettings,
} from 'twenty-shared/application';
import type { InputJsonSchema } from 'twenty-shared/logic-function';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
@ObjectType('LogicFunction')
@@ -69,7 +71,7 @@ export class LogicFunctionDTO {
@IsObject()
@IsOptional()
@Field(() => graphqlTypeJson, { nullable: true })
toolInputSchema?: object;
toolInputSchema?: InputJsonSchema;
@IsBoolean()
@Field()
@@ -13,6 +13,7 @@ import {
DatabaseEventTriggerSettings,
HttpRouteTriggerSettings,
} from 'twenty-shared/application';
import { type InputJsonSchema } from 'twenty-shared/logic-function';
import { SyncableEntity } from 'src/engine/workspace-manager/types/syncable-entity.interface';
import { type JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type';
@@ -59,7 +60,7 @@ export class LogicFunctionEntity
checksum: string | null;
@Column({ nullable: true, type: 'jsonb' })
toolInputSchema: JsonbProperty<object> | null;
toolInputSchema: JsonbProperty<InputJsonSchema> | null;
@Column({ nullable: false, default: false })
isTool: boolean;
@@ -3,6 +3,7 @@ import { Injectable } from '@nestjs/common';
import { join } from 'path';
import { v4 } from 'uuid';
import { SEED_LOGIC_FUNCTION_INPUT_SCHEMA } from 'twenty-shared/logic-function';
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service';
@@ -14,7 +15,6 @@ import { LogicFunctionMetadataService } from 'src/engine/metadata-modules/logic-
import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util';
import { fromFlatLogicFunctionToLogicFunctionDto } from 'src/engine/metadata-modules/logic-function/utils/from-flat-logic-function-to-logic-function-dto.util';
import { CreateLogicFunctionFromSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function-from-source.input';
import { SEED_LOGIC_FUNCTION_INPUT_SCHEMA } from 'src/engine/core-modules/logic-function/logic-function-resource/constants/seed-logic-function-input-schema';
import { UpdateLogicFunctionFromSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function-from-source.input';
import { getLogicFunctionSubfolderForFromSource } from 'src/engine/metadata-modules/logic-function/utils/get-logic-function-subfolder-for-from-source';
import {
@@ -54,6 +54,9 @@ export class UpdateLogicFunctionActionHandlerService extends WorkspaceMigrationR
LogicFunctionEntity,
);
await logicFunctionRepository.update({ id: entityId, workspaceId }, update);
await logicFunctionRepository.update(
{ id: entityId, workspaceId },
update as Parameters<typeof logicFunctionRepository.update>[1],
);
}
}