fix(ai) - Fix date stripped from agent tool output (#22443)
https://discord.com/channels/1130383047699738754/1522138489238458569 **Summary** Fix a bug where Date objects (returned by TypeORM for createdAt, updatedAt, deletedAt columns) were silently dropped from AI agent tool responses stripEmptyValues treated Date instances as empty objects because Object.entries(new Date()) returns [], causing the function to discard them Add instanceof Date guard before the generic object branch so Date values pass through unchanged **Root cause** TypeORM marks createdAt/updatedAt/deletedAt as special columns (createDate/updateDate/deleteDate) and returns them as JavaScript Date objects rather than strings. The stripEmptyValues utility checked typeof value === 'object' (true for Date), then called Object.entries() on it -- which yields an empty array since Date has no own enumerable properties -- and concluded the value was "empty". The existing tests used string dates ('2024-01-01') instead of actual Date objects, so the bug was never caught. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22443?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
This commit is contained in:
+41
@@ -141,6 +141,47 @@ describe('stripEmptyValues', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve Date objects', () => {
|
||||
const date = new Date('2024-01-15T10:30:00.000Z');
|
||||
|
||||
expect(stripEmptyValues({ createdAt: date, name: 'Test' })).toEqual({
|
||||
createdAt: date,
|
||||
name: 'Test',
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve Date objects inside nested records', () => {
|
||||
const createdAt = new Date('2024-01-15T10:30:00.000Z');
|
||||
const updatedAt = new Date('2024-02-20T14:00:00.000Z');
|
||||
|
||||
const input = {
|
||||
result: {
|
||||
records: [
|
||||
{
|
||||
id: 'abc-123',
|
||||
name: 'Acme',
|
||||
createdAt,
|
||||
updatedAt,
|
||||
deletedAt: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
expect(stripEmptyValues(input)).toEqual({
|
||||
result: {
|
||||
records: [
|
||||
{
|
||||
id: 'abc-123',
|
||||
name: 'Acme',
|
||||
createdAt,
|
||||
updatedAt,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle primitive values', () => {
|
||||
expect(stripEmptyValues(42)).toBe(42);
|
||||
expect(stripEmptyValues('hello')).toBe('hello');
|
||||
|
||||
+7
@@ -1,11 +1,18 @@
|
||||
// Recursively strips null, undefined, empty strings, empty objects,
|
||||
// and empty arrays from a value. Returns undefined if the entire
|
||||
|
||||
import { isDate } from '@sniptt/guards';
|
||||
|
||||
// value is empty so the caller can decide whether to include it.
|
||||
export const stripEmptyValues = (value: unknown): unknown => {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (isDate(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
const cleaned = value
|
||||
.map(stripEmptyValues)
|
||||
|
||||
Reference in New Issue
Block a user