fix: exclude system objects and workflow/dashboard from AI/MCP write tool descriptors (#20973)

## Summary

fix: exclude system join objects from AI/MCP create/update/delete tool
descriptors

Closes #20403

---
AI was used for assistance.

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
Matt Van Horn
2026-05-27 11:01:11 -07:00
committed by GitHub
parent c0cbe67bcd
commit de7daaa81a
18 changed files with 283 additions and 115 deletions
@@ -0,0 +1,45 @@
import { canObjectBeManagedByAutomation } from '@/workflow/utils/canObjectBeManagedByAutomation';
describe('canObjectBeManagedByAutomation', () => {
it('should return true for a standard non-blocked object', () => {
expect(canObjectBeManagedByAutomation({ nameSingular: 'company' })).toBe(
true,
);
});
it('should return true for noteTarget and taskTarget', () => {
expect(canObjectBeManagedByAutomation({ nameSingular: 'noteTarget' })).toBe(
true,
);
expect(canObjectBeManagedByAutomation({ nameSingular: 'taskTarget' })).toBe(
true,
);
});
it('should return true for attachment and timelineActivity', () => {
expect(canObjectBeManagedByAutomation({ nameSingular: 'attachment' })).toBe(
true,
);
expect(
canObjectBeManagedByAutomation({ nameSingular: 'timelineActivity' }),
).toBe(true);
});
it.each([
'workflow',
'workflowVersion',
'workflowRun',
'workflowAutomatedTrigger',
'workspaceMember',
'dashboard',
'message',
'messageThread',
'messageChannelMessageAssociation',
'messageParticipant',
'calendarEvent',
'calendarEventParticipant',
'calendarChannelEventAssociation',
])('should return false for %s', (nameSingular) => {
expect(canObjectBeManagedByAutomation({ nameSingular })).toBe(false);
});
});
@@ -1,57 +0,0 @@
import { canObjectBeManagedByWorkflow } from '@/workflow/utils/canObjectBeManagedByWorkflow';
describe('canObjectBeManagedByWorkflow', () => {
it('should return true for non-system, non-excluded objects', () => {
expect(
canObjectBeManagedByWorkflow({
nameSingular: 'company',
isSystem: false,
}),
).toBe(true);
});
it('should return false for system objects', () => {
expect(
canObjectBeManagedByWorkflow({
nameSingular: 'company',
isSystem: true,
}),
).toBe(false);
});
it('should return false for workflow object', () => {
expect(
canObjectBeManagedByWorkflow({
nameSingular: 'workflow',
isSystem: false,
}),
).toBe(false);
});
it('should return false for workflowVersion object', () => {
expect(
canObjectBeManagedByWorkflow({
nameSingular: 'workflowVersion',
isSystem: false,
}),
).toBe(false);
});
it('should return false for workflowRun object', () => {
expect(
canObjectBeManagedByWorkflow({
nameSingular: 'workflowRun',
isSystem: false,
}),
).toBe(false);
});
it('should return false for dashboard object', () => {
expect(
canObjectBeManagedByWorkflow({
nameSingular: 'dashboard',
isSystem: false,
}),
).toBe(false);
});
});
@@ -0,0 +1,11 @@
import { OBJECTS_BLOCKED_FROM_AUTOMATION } from '../constants/ObjectsBlockedFromAutomation';
export const canObjectBeManagedByAutomation = ({
nameSingular,
}: {
nameSingular: string;
}): boolean => {
return !OBJECTS_BLOCKED_FROM_AUTOMATION.includes(
nameSingular as (typeof OBJECTS_BLOCKED_FROM_AUTOMATION)[number],
);
};
@@ -1,19 +0,0 @@
export const canObjectBeManagedByWorkflow = ({
nameSingular,
isSystem,
}: {
nameSingular: string;
isSystem: boolean;
}) => {
const excludedNonSystemObjectMetadataItemNames = [
'workflow',
'workflowVersion',
'workflowRun',
'dashboard',
];
return (
!excludedNonSystemObjectMetadataItemNames.includes(nameSingular) &&
!isSystem
);
};