Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 33 additions & 8 deletions src/actors.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Ajv } from 'ajv';
import { ApifyClient } from 'apify-client';

import { ACTOR_ADDITIONAL_INSTRUCTIONS, defaults, MAX_DESCRIPTION_LENGTH, ACTOR_README_MAX_LENGTH } from './const.js';
import { ACTOR_ADDITIONAL_INSTRUCTIONS, defaults, MAX_DESCRIPTION_LENGTH, ACTOR_README_MAX_LENGTH, ACTOR_ENUM_MAX_LENGTH } from './const.js';
import { log } from './logger.js';
import type { ActorDefinitionPruned, ActorDefinitionWithDesc, IActorInputSchema, ISchemaProperties, Tool } from './types.js';

Expand Down Expand Up @@ -78,15 +78,40 @@ function pruneActorDefinition(response: ActorDefinitionWithDesc): ActorDefinitio
}

/**
* Shortens the description and enum values of schema properties.
* Helper function to shorten the enum list if it is too long.
*
* @param {string[]} enumList - The list of enum values to be shortened.
* @returns {string[] | undefined} - The shortened enum list or undefined if the list is too long.
*/
export function shortenEnum(enumList: string[]): string[] | undefined {
let charCount = 0;
const resultEnumList = enumList.filter((enumValue) => {
charCount += enumValue.length;
return charCount <= ACTOR_ENUM_MAX_LENGTH;
});

return resultEnumList.length > 0 ? resultEnumList : undefined;
}

/**
* Shortens the description, enum, and items.enum properties of the schema properties.
* @param properties
*/
export function shortenProperties(properties: { [key: string]: ISchemaProperties}): { [key: string]: ISchemaProperties } {
for (const property of Object.values(properties)) {
if (property.description.length > MAX_DESCRIPTION_LENGTH) {
property.description = `${property.description.slice(0, MAX_DESCRIPTION_LENGTH)}...`;
}

if (property.enum && property.enum?.length > 0) {
property.enum = shortenEnum(property.enum);
}

if (property.items?.enum && property.items.enum.length > 0) {
property.items.enum = shortenEnum(property.items.enum);
}
}

return properties;
}

Expand Down Expand Up @@ -282,7 +307,7 @@ function buildNestedProperties(properties: Record<string, ISchemaProperties>): R
* Tool name can't contain /, so it is replaced with _
*
* The input schema processing workflow:
* 1. Properties are marked as required using markInputPropertiesAsRequired()
* 1. Properties are marked as required using markInputPropertiesAsRequired() to add "REQUIRED" prefix to descriptions
* 2. Nested properties are built by analyzing editor type (proxy, requestListSources) using buildNestedProperties()
* 3. Properties are filtered using filterSchemaProperties()
* 4. Properties are shortened using shortenProperties()
Expand All @@ -298,11 +323,11 @@ export async function getActorsAsTools(actors: string[]): Promise<Tool[]> {
for (const result of results) {
if (result) {
if (result.input && 'properties' in result.input && result.input) {
const propertiesMarkedAsRequired = markInputPropertiesAsRequired(result.input);
const propertiesObjectsBuilt = buildNestedProperties(propertiesMarkedAsRequired);
const propertiesFiltered = filterSchemaProperties(propertiesObjectsBuilt);
const propertiesShortened = shortenProperties(propertiesFiltered);
result.input.properties = addEnumsToDescriptionsWithExamples(propertiesShortened);
result.input.properties = markInputPropertiesAsRequired(result.input);
result.input.properties = buildNestedProperties(result.input.properties);
result.input.properties = filterSchemaProperties(result.input.properties);
result.input.properties = shortenProperties(result.input.properties);
result.input.properties = addEnumsToDescriptionsWithExamples(result.input.properties);
}
try {
const memoryMbytes = result.defaultRunOptions?.memoryMbytes || defaults.maxMemoryMbytes;
Expand Down
3 changes: 2 additions & 1 deletion src/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export const defaults = {
maxMemoryMbytes: 4096,
};

export const ACTOR_README_MAX_LENGTH = 5000;
export const ACTOR_README_MAX_LENGTH = 5_000;
export const ACTOR_ENUM_MAX_LENGTH = 200;
export const ACTOR_OUTPUT_MAX_CHARS_PER_ITEM = 5_000;
export const ACTOR_OUTPUT_TRUNCATED_MESSAGE = `Output was truncated because it will not fit into context.`
+ `There is no reason to call this tool again!`;
Expand Down
17 changes: 16 additions & 1 deletion tests/actors-test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { describe, it, expect } from 'vitest';

import { actorNameToToolName, inferArrayItemType } from '../src/actors.js';
import { actorNameToToolName, inferArrayItemType, shortenEnum } from '../src/actors.js';
import { ACTOR_ENUM_MAX_LENGTH } from '../src/const.js';

describe('actors', () => {
describe('actorNameToToolName', () => {
Expand Down Expand Up @@ -39,5 +40,19 @@ describe('actors', () => {
};
expect(inferArrayItemType(property)).toBe('string');
});

it('shorten enum list', () => {
const enumList: string[] = [];
const wordLength = 10;
const wordCount = 30;

for (let i = 0; i < wordCount; i++) {
enumList.push('a'.repeat(wordLength));
}

const shortenedList = shortenEnum(enumList);

expect(shortenedList?.length || 0).toBe(ACTOR_ENUM_MAX_LENGTH / wordLength);
});
});
});
Loading