import { consolidatedToolDefinitions } from '../tools/catalog/consolidated-tool-definitions.js'; import type { PrimitiveSchema } from '../utils/interaction/elicitation.js'; import type { Logger } from '../utils/logging/logger.js'; type ElicitFunction = ( message: string, schema: { type: 'object'; properties: Record; required: string[] }, options: Record ) => Promise<{ ok?: boolean; value?: Record } | undefined>; export async function maybeElicitMissingArgs( name: string, args: Record, elicitFn: unknown, timeoutMs: number, logger: Logger ): Promise> { try { if (typeof elicitFn !== 'function') return args; const toolDef = (consolidatedToolDefinitions as Array>).find(tool => tool.name === name) as Record | undefined; const inputSchema = toolDef?.inputSchema as Record | undefined; if (!inputSchema) return args; const primitiveProps = getMissingPrimitiveProps(inputSchema, args); if (Object.keys(primitiveProps).length === 0) return args; const elicitOptions: Record = { fallback: async () => ({ ok: false, error: 'missing-params' }) }; if (Number.isFinite(timeoutMs)) { elicitOptions.timeoutMs = timeoutMs; } const elicitRes = await (elicitFn as ElicitFunction)( `Provide missing parameters for ${name}`, { type: 'object', properties: primitiveProps, required: Object.keys(primitiveProps) }, elicitOptions ); if (elicitRes && elicitRes.ok && elicitRes.value) { return { ...args, ...elicitRes.value }; } } catch (e) { const message = e instanceof Error ? e.message : String(e); logger.debug('Generic elicitation prefill skipped', { err: message }); } return args; } function getMissingPrimitiveProps(inputSchema: Record, args: Record): Record { const props = (inputSchema.properties || {}) as Record>; const required: string[] = Array.isArray(inputSchema.required) ? inputSchema.required as string[] : []; const missing = required.filter((key: string) => { const value = args[key]; if (value === undefined || value === null) return true; if (typeof value === 'string' && value.trim() === '') return true; return false; }); const primitiveProps: Record = {}; for (const key of missing) { const property = props[key]; if (!property || typeof property !== 'object') continue; const type = (property.type || '').toString(); const isEnum = Array.isArray(property.enum); if (type === 'string' || type === 'number' || type === 'integer' || type === 'boolean' || isEnum) { const schemaType = (isEnum ? 'string' : type) as 'string' | 'number' | 'integer' | 'boolean'; primitiveProps[key] = { type: schemaType, title: typeof property.title === 'string' ? property.title : undefined, description: typeof property.description === 'string' ? property.description : undefined, enum: Array.isArray(property.enum) ? (property.enum as string[]) : undefined, enumNames: Array.isArray(property.enumNames) ? (property.enumNames as string[]) : undefined, minimum: typeof property.minimum === 'number' ? property.minimum : undefined, maximum: typeof property.maximum === 'number' ? property.maximum : undefined, minLength: typeof property.minLength === 'number' ? property.minLength : undefined, maxLength: typeof property.maxLength === 'number' ? property.maxLength : undefined, pattern: typeof property.pattern === 'string' ? property.pattern : undefined, format: typeof property.format === 'string' ? (property.format as 'email' | 'uri' | 'date' | 'date-time') : undefined, default: (typeof property.default === 'string' || typeof property.default === 'number' || typeof property.default === 'boolean') ? property.default : undefined } as PrimitiveSchema; } } return primitiveProps; }