Skip to content

Commit eb38160

Browse files
authored
fix: Actor input transform array items type inference (#225)
1 parent 22eddd0 commit eb38160

File tree

3 files changed

+117
-31
lines changed

3 files changed

+117
-31
lines changed

src/tools/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,8 @@ export function transformActorInputSchemaProperties(input: Readonly<IActorInputS
284284
const inputClone: IActorInputSchema = structuredClone(input);
285285
let transformedProperties = markInputPropertiesAsRequired(inputClone);
286286
transformedProperties = buildApifySpecificProperties(transformedProperties);
287-
transformedProperties = filterSchemaProperties(transformedProperties);
288287
transformedProperties = inferArrayItemsTypeIfMissing(transformedProperties);
288+
transformedProperties = filterSchemaProperties(transformedProperties);
289289
transformedProperties = shortenProperties(transformedProperties);
290290
transformedProperties = addEnumsToDescriptionsWithExamples(transformedProperties);
291291
transformedProperties = encodeDotPropertyNames(transformedProperties);

tests/unit/tools.actor.test.ts

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { describe, expect, it } from 'vitest';
22

3-
import { ACTOR_ENUM_MAX_LENGTH } from '../../src/const.js';
4-
import { actorNameToToolName, inferArrayItemType, shortenEnum } from '../../src/tools/utils.js';
3+
import { actorNameToToolName } from '../../src/tools/utils.js';
54

65
describe('actors', () => {
76
describe('actorNameToToolName', () => {
@@ -27,32 +26,5 @@ describe('actors', () => {
2726
const expected = 'a'.repeat(64);
2827
expect(actorNameToToolName(longName)).toBe(expected);
2928
});
30-
31-
it('infers array item type from editor', () => {
32-
const property = {
33-
type: 'array',
34-
editor: 'stringList',
35-
title: '',
36-
description: '',
37-
enum: [],
38-
default: '',
39-
prefill: '',
40-
};
41-
expect(inferArrayItemType(property)).toBe('string');
42-
});
43-
44-
it('shorten enum list', () => {
45-
const enumList: string[] = [];
46-
const wordLength = 10;
47-
const wordCount = 30;
48-
49-
for (let i = 0; i < wordCount; i++) {
50-
enumList.push('a'.repeat(wordLength));
51-
}
52-
53-
const shortenedList = shortenEnum(enumList);
54-
55-
expect(shortenedList?.length || 0).toBe(ACTOR_ENUM_MAX_LENGTH / wordLength);
56-
});
5729
});
5830
});

tests/unit/tools.utils.test.ts

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest';
22

33
import { ACTOR_ENUM_MAX_LENGTH, ACTOR_MAX_DESCRIPTION_LENGTH } from '../../src/const.js';
44
import { buildApifySpecificProperties, decodeDotPropertyNames, encodeDotPropertyNames,
5-
markInputPropertiesAsRequired, shortenProperties,
5+
inferArrayItemsTypeIfMissing, inferArrayItemType, markInputPropertiesAsRequired, shortenEnum, shortenProperties,
66
transformActorInputSchemaProperties } from '../../src/tools/utils.js';
77
import type { IActorInputSchema, ISchemaProperties } from '../../src/types.js';
88

@@ -786,4 +786,118 @@ describe('transformActorInputSchemaProperties', () => {
786786
transformActorInputSchemaProperties(input);
787787
expect(input).toEqual(inputCopy);
788788
});
789+
790+
it('should build array items property correctly for stringList editor with place IDs', () => {
791+
const input: IActorInputSchema = {
792+
type: 'object',
793+
schemaVersion: 1,
794+
properties: {
795+
placeIds: {
796+
title: '🗃 Place IDs',
797+
type: 'array',
798+
description: 'List of place IDs.',
799+
editor: 'stringList',
800+
},
801+
},
802+
};
803+
804+
const result = transformActorInputSchemaProperties(input);
805+
806+
// Verify that array items type was correctly inferred and set
807+
expect(result.placeIds.type).toBe('array');
808+
expect(result.placeIds.items).toBeDefined();
809+
expect(result.placeIds.items?.type).toBe('string');
810+
expect(result.placeIds.items?.title).toBe('🗃 Place IDs');
811+
expect(result.placeIds.items?.description).toBe(input.properties.placeIds.description);
812+
813+
// Verify that the property name was encoded (dots replaced with -dot-)
814+
expect(result.placeIds).toBeDefined();
815+
816+
// Verify that other transformations were applied
817+
expect(result.placeIds.title).toBe('🗃 Place IDs');
818+
expect(result.placeIds.description).toBe(input.properties.placeIds.description);
819+
});
820+
});
821+
822+
describe('inferArrayItemType', () => {
823+
it('infers array item type from editor', () => {
824+
const property = {
825+
type: 'array',
826+
editor: 'stringList',
827+
title: '',
828+
description: '',
829+
enum: [],
830+
default: '',
831+
prefill: '',
832+
};
833+
expect(inferArrayItemType(property)).toBe('string');
834+
});
835+
836+
it('infers string type for stringList editor with place IDs input', () => {
837+
const property: ISchemaProperties = {
838+
title: 'Place IDs',
839+
type: 'array',
840+
description: 'List of place IDs.',
841+
editor: 'stringList',
842+
};
843+
844+
expect(inferArrayItemType(property)).toBe('string');
845+
});
846+
});
847+
848+
describe('inferArrayItemsTypeIfMissing', () => {
849+
it('should infer and set items type for array property with stringList editor', () => {
850+
const properties: { [key: string]: ISchemaProperties } = {
851+
placeIds: {
852+
title: '🗃 Place IDs',
853+
type: 'array',
854+
description: 'List of place IDs.',
855+
editor: 'stringList',
856+
},
857+
};
858+
859+
const result = inferArrayItemsTypeIfMissing(properties);
860+
861+
expect(result.placeIds.items).toBeDefined();
862+
expect(result.placeIds.items?.type).toBe('string');
863+
expect(result.placeIds.items?.title).toBe('🗃 Place IDs');
864+
expect(result.placeIds.items?.description).toBe(properties.placeIds.description);
865+
});
866+
867+
it('should not modify array properties that already have items.type defined', () => {
868+
const properties: { [key: string]: ISchemaProperties } = {
869+
existingArray: {
870+
title: 'Existing Array',
871+
type: 'array',
872+
description: 'Array with existing items type',
873+
items: {
874+
type: 'number',
875+
title: 'Number Item',
876+
description: 'A number item',
877+
},
878+
},
879+
};
880+
881+
const result = inferArrayItemsTypeIfMissing(properties);
882+
883+
expect(result.existingArray.items?.type).toBe('number');
884+
expect(result.existingArray.items?.title).toBe('Number Item');
885+
expect(result.existingArray.items?.description).toBe('A number item');
886+
});
887+
});
888+
889+
describe('shortenEnum', () => {
890+
it('shorten enum list', () => {
891+
const enumList: string[] = [];
892+
const wordLength = 10;
893+
const wordCount = 30;
894+
895+
for (let i = 0; i < wordCount; i++) {
896+
enumList.push('a'.repeat(wordLength));
897+
}
898+
899+
const shortenedList = shortenEnum(enumList);
900+
901+
expect(shortenedList?.length || 0).toBe(ACTOR_ENUM_MAX_LENGTH / wordLength);
902+
});
789903
});

0 commit comments

Comments
 (0)