From 01bb2f4ab261eb86baa2dcbfa24a5841f7d0ee74 Mon Sep 17 00:00:00 2001
From: Harshit Raizada <112213410+dankgarlic1@users.noreply.github.com>
Date: Thu, 18 Jun 2026 14:01:13 +0530
Subject: [PATCH] fix: enforce strict rules for currency value handling by ai
chatbot (#21470)
opportunity:
fix:
closes #21419
---------
Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
---
.../zod-schemas/record-properties.zod-schema.ts | 12 +++++++++---
.../zod-schemas/shared-filter-defs.zod-schema.ts | 3 +++
.../zod-schemas/shared-value-defs.zod-schema.ts | 14 +++++++++++++-
3 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/packages/twenty-server/src/engine/core-modules/record-crud/zod-schemas/record-properties.zod-schema.ts b/packages/twenty-server/src/engine/core-modules/record-crud/zod-schemas/record-properties.zod-schema.ts
index 859a1f3cee..8ba5588170 100644
--- a/packages/twenty-server/src/engine/core-modules/record-crud/zod-schemas/record-properties.zod-schema.ts
+++ b/packages/twenty-server/src/engine/core-modules/record-crud/zod-schemas/record-properties.zod-schema.ts
@@ -14,6 +14,8 @@ import { type ObjectMetadataForToolSchema } from 'src/engine/core-modules/record
import {
AddressValueOptionalSchema,
AddressValueSchema,
+ CurrencyResponseValueOptionalSchema,
+ CurrencyResponseValueSchema,
CurrencyValueOptionalSchema,
CurrencyValueSchema,
EmailsValueOptionalSchema,
@@ -188,9 +190,13 @@ export const generateRecordPropertiesZodSchema = (
}
case FieldMetadataType.CURRENCY: {
- const baseSchema = field.isNullable
- ? CurrencyValueOptionalSchema
- : CurrencyValueSchema;
+ const baseSchema = forResponse
+ ? field.isNullable
+ ? CurrencyResponseValueOptionalSchema
+ : CurrencyResponseValueSchema
+ : field.isNullable
+ ? CurrencyValueOptionalSchema
+ : CurrencyValueSchema;
shape[field.name] = field.description
? baseSchema.describe(field.description)
diff --git a/packages/twenty-server/src/engine/core-modules/record-crud/zod-schemas/shared-filter-defs.zod-schema.ts b/packages/twenty-server/src/engine/core-modules/record-crud/zod-schemas/shared-filter-defs.zod-schema.ts
index 4a0522776b..f87acecb1a 100644
--- a/packages/twenty-server/src/engine/core-modules/record-crud/zod-schemas/shared-filter-defs.zod-schema.ts
+++ b/packages/twenty-server/src/engine/core-modules/record-crud/zod-schemas/shared-filter-defs.zod-schema.ts
@@ -249,6 +249,9 @@ export const CurrencyFilterSchema = z
in: z.array(z.number()).optional().describe('In array'),
is: NullCheckEnum.optional(),
})
+ .describe(
+ 'Currency amount in micros (1 unit = 1,000,000 micros). Multiply the user-provided amount by 1,000,000 to build this filter.',
+ )
.optional(),
currencyCode: z
.object({
diff --git a/packages/twenty-server/src/engine/core-modules/record-crud/zod-schemas/shared-value-defs.zod-schema.ts b/packages/twenty-server/src/engine/core-modules/record-crud/zod-schemas/shared-value-defs.zod-schema.ts
index 11e7c1bea9..445ba47bb6 100644
--- a/packages/twenty-server/src/engine/core-modules/record-crud/zod-schemas/shared-value-defs.zod-schema.ts
+++ b/packages/twenty-server/src/engine/core-modules/record-crud/zod-schemas/shared-value-defs.zod-schema.ts
@@ -17,12 +17,24 @@ export const LinksValueSchema = z.object({
});
export const LinksValueOptionalSchema = LinksValueSchema.optional();
+const CURRENCY_WRITE_DESCRIPTION =
+ 'Currency amount in micros (1 unit = 1,000,000 micros). Multiply the user-provided amount by 1,000,000 before writing.';
+const CURRENCY_READ_DESCRIPTION =
+ 'Currency amount in micros (1 unit = 1,000,000 micros). Divide by 1,000,000 to display to users.';
+
export const CurrencyValueSchema = z.object({
- amountMicros: z.number().optional(),
+ amountMicros: z.number().optional().describe(CURRENCY_WRITE_DESCRIPTION),
currencyCode: z.string().optional(),
});
export const CurrencyValueOptionalSchema = CurrencyValueSchema.optional();
+export const CurrencyResponseValueSchema = z.object({
+ amountMicros: z.number().optional().describe(CURRENCY_READ_DESCRIPTION),
+ currencyCode: z.string().optional(),
+});
+export const CurrencyResponseValueOptionalSchema =
+ CurrencyResponseValueSchema.optional();
+
export const FullNameValueSchema = z.object({
firstName: z.string().optional(),
lastName: z.string().optional(),