11import type { Client } from '@modelcontextprotocol/sdk/client/index.js' ;
2+ import type { ValidateFunction } from 'ajv' ;
23import { Ajv } from 'ajv' ;
34import type { ActorCallOptions , ActorRun , Dataset , PaginatedList } from 'apify-client' ;
45import { z } from 'zod' ;
@@ -26,12 +27,32 @@ import {
2627 addEnumsToDescriptionsWithExamples ,
2728 buildNestedProperties ,
2829 filterSchemaProperties ,
30+ getToolSchemaID ,
2931 markInputPropertiesAsRequired ,
3032 shortenProperties ,
3133} from './utils.js' ;
3234
3335const ajv = new Ajv ( { coerceTypes : 'array' , strict : false } ) ;
3436
37+ // source https://github.com/ajv-validator/ajv/issues/1413#issuecomment-867064234
38+ function fixedCompile ( schema : object ) : ValidateFunction < unknown > {
39+ const validate = ajv . compile ( schema ) ;
40+ ajv . removeSchema ( schema ) ;
41+
42+ // Force reset values that aren't reset with removeSchema
43+ /* eslint-disable no-underscore-dangle */
44+ /* eslint-disable @typescript-eslint/no-explicit-any */
45+ ( ajv . scope as any ) . _values . schema ! . delete ( schema ) ;
46+ ( ajv . scope as any ) . _values . validate ! . delete ( validate ) ;
47+ const schemaIdx = ( ajv . scope as any ) . _scope . schema . indexOf ( schema ) ;
48+ const validateIdx = ( ajv . scope as any ) . _scope . validate . indexOf ( validate ) ;
49+ if ( schemaIdx !== - 1 ) ( ajv . scope as any ) . _scope . schema . splice ( schemaIdx , 1 ) ;
50+ if ( validateIdx !== - 1 ) ( ajv . scope as any ) . _scope . validate . splice ( validateIdx , 1 ) ;
51+ /* eslint-enable @typescript-eslint/no-explicit-any */
52+ /* eslint-enable no-underscore-dangle */
53+ return validate ;
54+ }
55+
3556// Define a named return type for callActorGetDataset
3657export type CallActorGetDatasetResult = {
3758 actorRun : ActorRun ;
@@ -141,12 +162,16 @@ export async function getNormalActorsAsTools(
141162 const actorIDOrName = actorsToLoad [ i ] ;
142163
143164 if ( result ) {
165+ const schemaID = getToolSchemaID ( result . actorFullName ) ;
144166 if ( result . input && 'properties' in result . input && result . input ) {
145167 result . input . properties = markInputPropertiesAsRequired ( result . input ) ;
146168 result . input . properties = buildNestedProperties ( result . input . properties ) ;
147169 result . input . properties = filterSchemaProperties ( result . input . properties ) ;
148170 result . input . properties = shortenProperties ( result . input . properties ) ;
149171 result . input . properties = addEnumsToDescriptionsWithExamples ( result . input . properties ) ;
172+ // Add schema $id, each valid JSON schema should have a unique $id
173+ // see https://json-schema.org/understanding-json-schema/basics#declaring-a-unique-identifier
174+ result . input . $id = schemaID ;
150175 }
151176 try {
152177 const memoryMbytes = result . defaultRunOptions ?. memoryMbytes || ACTOR_MAX_MEMORY_MBYTES ;
@@ -157,7 +182,7 @@ export async function getNormalActorsAsTools(
157182 actorFullName : result . actorFullName ,
158183 description : `${ result . description } Instructions: ${ ACTOR_ADDITIONAL_INSTRUCTIONS } ` ,
159184 inputSchema : result . input || { } ,
160- ajvValidate : ajv . compile ( result . input || { } ) ,
185+ ajvValidate : fixedCompile ( result . input || { } ) ,
161186 memoryMbytes : memoryMbytes > ACTOR_MAX_MEMORY_MBYTES ? ACTOR_MAX_MEMORY_MBYTES : memoryMbytes ,
162187 } ,
163188 } ;
0 commit comments