Skip to content

Commit 95960d5

Browse files
committed
fix(knowledge): leave values at the limit untouched and refuse over-long tag values on the tag-data and tag-update paths
1 parent d187644 commit 95960d5

6 files changed

Lines changed: 45 additions & 4 deletions

File tree

‎apps/sim/lib/knowledge/application/documents.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ import {
6868
toKnowledgeTagFilterConditions,
6969
} from '@/lib/knowledge/tags/filter-resolution'
7070
import { getDocumentTagDefinitions } from '@/lib/knowledge/tags/service'
71-
import { validateTagValue } from '@/lib/knowledge/tags/utils'
71+
import { validateTagValue, validateTagValueLength } from '@/lib/knowledge/tags/utils'
7272
import { StorageService } from '@/lib/uploads'
7373
import { generateKnowledgeBaseFileKey } from '@/lib/uploads/contexts/knowledge-base/knowledge-base-file-manager'
7474
import { recordKnowledgeBaseFileOwnership } from '@/lib/uploads/server/metadata'
@@ -252,7 +252,9 @@ async function resolveKnowledgeDocumentTagValueUpdates(
252252
`Tag "${definition.displayName}" requires a value; use null to clear it`
253253
)
254254
}
255-
const validationError = validateTagValue(definition.displayName, value, definition.fieldType)
255+
const validationError =
256+
validateTagValueLength(definition.displayName, value) ??
257+
validateTagValue(definition.displayName, value, definition.fieldType)
256258
if (validationError) {
257259
throw new OrchestrationError('validation', validationError)
258260
}

‎apps/sim/lib/knowledge/connectors/sync-persistence.test.ts‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,16 @@ describe('resolveTagMapping', () => {
450450
expect(tags?.tag2).toBe('Purchasing')
451451
})
452452

453+
it('keeps a value exactly at the limit untouched', () => {
454+
const atLimit = 'z'.repeat(512)
455+
const tags = resolveTagMapping(
456+
'fixture',
457+
{ label: atLimit },
458+
{ tagSlotMapping: { label: 'tag1' } }
459+
)
460+
expect(tags?.tag1).toBe(atLimit)
461+
})
462+
453463
it('cuts by code point so a bounded value never ends in half a surrogate pair', () => {
454464
const tags = resolveTagMapping(
455465
'fixture',

‎apps/sim/lib/knowledge/connectors/sync-persistence.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ const INDEXED_TEXT_CUT_SUFFIX = '...'
184184
* never inside a surrogate pair. The result always passes the document APIs' own bound.
185185
*/
186186
function boundIndexedText(value: string): string {
187+
if (value.length <= MAX_DOCUMENT_INDEXED_TEXT_LENGTH) return value
187188
return truncateAtCodePoint(
188189
value,
189190
MAX_DOCUMENT_INDEXED_TEXT_LENGTH - INDEXED_TEXT_CUT_SUFFIX.length,

‎apps/sim/lib/knowledge/documents/service.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ import {
179179
parseNumberValue,
180180
uncompilableTagFilterError,
181181
validateTagValue,
182+
validateTagValueLength,
182183
} from '@/lib/knowledge/tags/utils'
183184
import type { ProcessedDocumentTags } from '@/lib/knowledge/types'
184185
import { embeddingVectorValues } from '@/lib/knowledge/vector-columns'
@@ -552,7 +553,9 @@ function resolveDocumentTags(
552553

553554
const rawValue = typeof tag.value === 'string' ? tag.value.trim() : tag.value
554555
const actualFieldType = existingDef.fieldType || fieldType
555-
const validationError = validateTagValue(tagName, String(rawValue), actualFieldType)
556+
const validationError =
557+
validateTagValueLength(tagName, String(rawValue)) ??
558+
validateTagValue(tagName, String(rawValue), actualFieldType)
556559
if (validationError) {
557560
typeErrors.push(validationError)
558561
}

‎apps/sim/lib/knowledge/tags/utils.test.ts‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
* @vitest-environment node
33
*/
44
import { describe, expect, it } from 'vitest'
5-
import { coerceTagFilterValue, validateTagValue } from '@/lib/knowledge/tags/utils'
5+
import {
6+
coerceTagFilterValue,
7+
validateTagValue,
8+
validateTagValueLength,
9+
} from '@/lib/knowledge/tags/utils'
610

711
describe('coerceTagFilterValue', () => {
812
it('accepts exactly what validateTagValue accepts', () => {
@@ -68,3 +72,12 @@ describe('validateTagValue', () => {
6872
expect(validateTagValue('name', 'anything', 'json')).toBeNull()
6973
})
7074
})
75+
76+
describe('validateTagValueLength', () => {
77+
it('accepts a value at the indexed-text limit and names the tag past it', () => {
78+
expect(validateTagValueLength('Labels', 'a'.repeat(512))).toBeNull()
79+
expect(validateTagValueLength('Labels', 'a'.repeat(513))).toBe(
80+
'Tag "Labels" cannot exceed 512 characters'
81+
)
82+
})
83+
})

‎apps/sim/lib/knowledge/tags/utils.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { OrchestrationError } from '@/lib/core/orchestration/types'
2+
import { MAX_DOCUMENT_INDEXED_TEXT_LENGTH } from '@/lib/knowledge/constants'
23

34
const DATE_ONLY_PATTERN = /^\d{4}-\d{2}-\d{2}$/
45

@@ -94,6 +95,17 @@ export function uncompilableTagFilterError(filter: {
9495
* Validate a tag value against its expected field type
9596
* Returns an error message if invalid, or null if valid
9697
*/
98+
/**
99+
* Text tag values sit under an index whose rows Postgres caps in size; a value past
100+
* {@link MAX_DOCUMENT_INDEXED_TEXT_LENGTH} would fail the document write itself, so it is
101+
* refused with a message naming the tag instead.
102+
*/
103+
export function validateTagValueLength(tagName: string, value: string): string | null {
104+
return value.length > MAX_DOCUMENT_INDEXED_TEXT_LENGTH
105+
? `Tag "${tagName}" cannot exceed ${MAX_DOCUMENT_INDEXED_TEXT_LENGTH} characters`
106+
: null
107+
}
108+
97109
export function validateTagValue(tagName: string, value: string, fieldType: string): string | null {
98110
if (fieldType !== 'boolean' && fieldType !== 'number' && fieldType !== 'date') return null
99111

0 commit comments

Comments
 (0)