Skip to content

Commit 73ba5e7

Browse files
committed
fix(gauge): count Unicode prompt characters correctly
1 parent 9ce4fd1 commit 73ba5e7

2 files changed

Lines changed: 30 additions & 1 deletion

File tree

‎apps/sim/tools/gauge/create_prompts.ts‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ import {
1717
import type { ToolConfig } from '@/tools/types'
1818
import { safeUrlPathSegment } from '@/tools/url-path'
1919

20+
const MAX_PROMPT_TEXT_LENGTH = 500
21+
22+
/** Matches Gauge's code-point limit without expanding oversized strings. */
23+
function isPromptTextWithinLimit(text: string): boolean {
24+
return (
25+
text.length <= MAX_PROMPT_TEXT_LENGTH ||
26+
(text.length <= MAX_PROMPT_TEXT_LENGTH * 2 && Array.from(text).length <= MAX_PROMPT_TEXT_LENGTH)
27+
)
28+
}
29+
2030
/** Validates the batch before selecting only the text Gauge sends to AI engines. */
2131
function parseGaugePrompts(value: unknown): GaugePromptIn[] {
2232
const parsed = parseGaugeJson(value, 'prompts')
@@ -28,7 +38,7 @@ function parseGaugePrompts(value: unknown): GaugePromptIn[] {
2838
!isRecordLike(prompt) ||
2939
typeof prompt.text !== 'string' ||
3040
!prompt.text.trim() ||
31-
prompt.text.length > 500 ||
41+
!isPromptTextWithinLimit(prompt.text) ||
3242
typeof prompt.topicId !== 'string' ||
3343
!prompt.topicId.trim()
3444
) {

‎apps/sim/tools/gauge/utils.test.ts‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,25 @@ describe('Gauge tracked prompt model input', () => {
6161
{ text: 'Compare analytics tools', topicId: 'top_other' },
6262
]
6363

64+
it.each([
65+
['surrogate pairs', '😀'.repeat(500)],
66+
['mixed Unicode and ASCII', `${'😀'.repeat(250)}${'a'.repeat(250)}`],
67+
])('accepts 500 code points containing %s without changing the text', (_label, text) => {
68+
expect(body({ ...requestParams, prompts: [{ text, topicId: 'top_example' }] })).toMatchObject({
69+
prompts: [{ text, topicId: 'top_example' }],
70+
})
71+
})
72+
73+
it.each([
74+
['mixed Unicode and ASCII', `${'😀'.repeat(251)}${'a'.repeat(250)}`],
75+
['ASCII', 'a'.repeat(501)],
76+
['surrogate pairs', '😀'.repeat(501)],
77+
])('rejects 501 code points containing %s', (_label, text) => {
78+
expect(() => body({ ...requestParams, prompts: [{ text, topicId: 'top_example' }] })).toThrow(
79+
'Each prompt must have text (1 to 500 characters) and a topicId'
80+
)
81+
})
82+
6483
it('selects prompt text and preserves control fields when rebuilding projected JSON', () => {
6584
const original = JSON.stringify(prompts)
6685
expect(select({ ...requestParams, prompts: original })).toEqual({

0 commit comments

Comments
 (0)