From 243d8c2fad8a6e0fc97db75bc1543a0c67ad4d50 Mon Sep 17 00:00:00 2001 From: babayaga Date: Mon, 7 Apr 2025 11:26:54 +0200 Subject: [PATCH] kbot cache object level --- .../examples/core/iterator-factory-example.js | 42 +++--- packages/kbot/dist-in/iterator.d.ts | 20 +-- packages/kbot/dist-in/iterator.js | 87 ++++++++---- .../examples/core/iterator-factory-example.ts | 43 +++--- packages/kbot/src/iterator.ts | 129 +++++++++++++----- 5 files changed, 209 insertions(+), 112 deletions(-) diff --git a/packages/kbot/dist-in/examples/core/iterator-factory-example.js b/packages/kbot/dist-in/examples/core/iterator-factory-example.js index 38da5506..ae9a8f1a 100644 --- a/packages/kbot/dist-in/examples/core/iterator-factory-example.js +++ b/packages/kbot/dist-in/examples/core/iterator-factory-example.js @@ -44,21 +44,21 @@ const exampleData = { // Field mappings definition const fieldMappings = [ { - jsonPath: '$..description', + jsonPath: '$.products.fruits[*].description', targetPath: null, options: { prompt: 'Make this description more engaging and detailed, around 20-30 words' } }, { - jsonPath: '$..nutrition', + jsonPath: '$.products.fruits[*].details.nutrition', targetPath: null, options: { prompt: 'Expand this nutrition information with 2-3 specific health benefits, around 25-35 words' } }, { - jsonPath: '$..name', + jsonPath: '$.products.fruits[*].name', targetPath: 'marketingName', options: { prompt: 'Generate a more appealing marketing name for this product' @@ -80,16 +80,6 @@ export async function factoryExample() { console.log("Starting iterator factory example"); console.log("========================================"); try { - // Clear the test-data folder - const outputPath = path.resolve('./tests/test-data/core/iterator-factory-data.json'); - const outputDir = path.dirname(outputPath); - if (!fs.existsSync(outputDir)) { - fs.mkdirSync(outputDir, { recursive: true }); - } - // Make sure the file is empty to start with a clean slate - if (fs.existsSync(outputPath)) { - fs.unlinkSync(outputPath); - } const data = JSON.parse(JSON.stringify(exampleData)); // Global options for all transformations const globalOptionsMixin = { @@ -105,19 +95,28 @@ export async function factoryExample() { errorCallback, filterCallback: async () => true, transformerFactory: (options) => createLLMTransformer(options, logger, cacheConfig), - logger: logger, + logger, cacheConfig }); // Use the iterator to transform the data console.log("First run - should transform and cache results:"); await iterator.transform(fieldMappings); + const outputPath = path.resolve('./tests/test-data/core/iterator-factory-data.json'); + const outputDir = path.dirname(outputPath); + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + // Make sure the file is empty to start with a clean slate + if (fs.existsSync(outputPath)) { + fs.unlinkSync(outputPath); + } write(outputPath, JSON.stringify(data, null, 2)); console.log("Transformation complete. Results saved to", outputPath); // Print the transformed data structure console.log("\nTransformed data structure:"); - console.log(JSON.stringify(data.products.fruits[0], null, 2).substring(0, 200) + "..."); + console.log(JSON.stringify(data.products.fruits[0], null, 2)); // Create a second instance with the same data to test cache - console.log("\n\n========================================"); + console.log("\n========================================"); console.log("Second run - should use cached results:"); console.log("========================================"); const data2 = JSON.parse(JSON.stringify(exampleData)); @@ -127,19 +126,16 @@ export async function factoryExample() { errorCallback, filterCallback: async () => true, transformerFactory: (options) => createLLMTransformer(options, logger, cacheConfig), - logger: logger, + logger, cacheConfig }); // Should use cached values await iterator2.transform(fieldMappings); console.log("\nBefore/After Comparison Example:"); console.log(`Original description: ${exampleData.products.fruits[0].description}`); - console.log(`Transformed description: ${data.products.fruits[0].description}`); + console.log(`Transformed description: ${data2.products.fruits[0].description}`); console.log(`Original name: ${exampleData.products.fruits[0].name}`); - // Check if name is an object with marketingName property - const name = data.products.fruits[0].name; - const marketingName = typeof name === 'object' && name !== null ? name.marketingName : 'Not available'; - console.log(`New marketing name: ${marketingName}`); + console.log(`Marketing name: ${data2.products.fruits[0].marketingName || 'Not available'}`); return data; } catch (error) { @@ -159,4 +155,4 @@ if (process.argv[1] && process.argv[1].includes('iterator-factory-example')) { console.error("Unhandled error:", error); }); } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXRlcmF0b3ItZmFjdG9yeS1leGFtcGxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2V4YW1wbGVzL2NvcmUvaXRlcmF0b3ItZmFjdG9yeS1leGFtcGxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxJQUFJLElBQUksS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbkQsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFFekIsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDN0UsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzdDLE9BQU8sRUFBZ0IsY0FBYyxFQUFFLG9CQUFvQixFQUFlLE1BQU0sbUJBQW1CLENBQUM7QUFFcEcsTUFBTSxLQUFLLEdBQUcsa0JBQWtCLENBQUMsNkJBQTZCLENBQUM7QUFDL0QsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDO0FBQzVCLE1BQU0sU0FBUyxHQUFHLENBQUMsQ0FBQztBQUVwQixNQUFNLE1BQU0sR0FBRztJQUNYLElBQUksRUFBRSxDQUFDLE9BQWUsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLE9BQU8sRUFBRSxDQUFDO0lBQzFELElBQUksRUFBRSxDQUFDLE9BQWUsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLE9BQU8sRUFBRSxDQUFDO0lBQzFELEtBQUssRUFBRSxDQUFDLE9BQWUsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxVQUFVLE9BQU8sRUFBRSxDQUFDO0lBQzlELEtBQUssRUFBRSxDQUFDLE9BQWUsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLE9BQU8sRUFBRSxDQUFDO0lBQzVELEtBQUssRUFBRSxDQUFDLE9B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 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXRlcmF0b3ItZmFjdG9yeS1leGFtcGxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2V4YW1wbGVzL2NvcmUvaXRlcmF0b3ItZmFjdG9yeS1leGFtcGxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxJQUFJLElBQUksS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbkQsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFFekIsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDN0UsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzdDLE9BQU8sRUFBZ0IsY0FBYyxFQUFFLG9CQUFvQixFQUFlLE1BQU0sbUJBQW1CLENBQUM7QUFFcEcsTUFBTSxLQUFLLEdBQUcsa0JBQWtCLENBQUMsNkJBQTZCLENBQUM7QUFDL0QsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDO0FBQzVCLE1BQU0sU0FBUyxHQUFHLENBQUMsQ0FBQztBQUVwQixNQUFNLE1BQU0sR0FBRztJQUNYLElBQUksRUFBRSxDQUFDLE9BQWUsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLE9BQU8sRUFBRSxDQUFDO0lBQzFELElBQUksRUFBRSxDQUFDLE9BQWUsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLE9BQU8sRUFBRSxDQUFDO0lBQzFELEtBQUssRUFBRSxDQUFDLE9BQWUsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxVQUFVLE9BQU8sRUFBRSxDQUFDO0lBQzlELEtBQUssRUFBRSxDQUFDLE9BQWUsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLE9BQU8sRUFBRSxDQUFDO0lBQzVELEtBQUssRUFBRSxDQUFDLE9B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 \ No newline at end of file diff --git a/packages/kbot/dist-in/iterator.d.ts b/packages/kbot/dist-in/iterator.d.ts index fd1d033d..3e0703db 100644 --- a/packages/kbot/dist-in/iterator.d.ts +++ b/packages/kbot/dist-in/iterator.d.ts @@ -1,5 +1,10 @@ import { IKBotTask } from '@polymech/ai-tools'; import { AsyncTransformer, ErrorCallback, FilterCallback } from './async-iterator.js'; +export interface ILogger { + info: (message: string) => void; + warn: (message: string) => void; + error: (message: string, error?: any) => void; +} export declare const removeEmptyObjects: (obj: any) => any; export interface FieldMapping { jsonPath: string; @@ -17,12 +22,7 @@ export interface CacheConfig { namespace?: string; expiration?: number; } -export declare function createLLMTransformer(options: IKBotTask, logger?: { - info: (message: string) => void; - warn: (message: string) => void; - error: (message: string, error?: any) => void; -}, cacheConfig?: CacheConfig): AsyncTransformer; -export declare function createIterator(obj: Record, optionsMixin: Partial, globalOptions?: { +export interface IOptions { throttleDelay?: number; concurrentTasks?: number; errorCallback?: ErrorCallback; @@ -30,11 +30,11 @@ export declare function createIterator(obj: Record, optionsMixin: P transformerFactory?: (options: IKBotTask) => AsyncTransformer; maxRetries?: number; retryDelay?: number; - logger?: { - error: (message: string, error?: any) => void; - }; + logger?: ILogger; cacheConfig?: CacheConfig; -}): IteratorFactory; +} +export declare function createLLMTransformer(options: IKBotTask, logger?: ILogger, cacheConfig?: CacheConfig): AsyncTransformer; +export declare function createIterator(obj: Record, optionsMixin: Partial, globalOptions?: IOptions): IteratorFactory; export declare function transformWithMappings(obj: Record, createTransformer: (options: IKBotTask) => AsyncTransformer, mappings: FieldMapping[], globalOptions?: { throttleDelay?: number; concurrentTasks?: number; diff --git a/packages/kbot/dist-in/iterator.js b/packages/kbot/dist-in/iterator.js index 95fa6b70..c51ba837 100644 --- a/packages/kbot/dist-in/iterator.js +++ b/packages/kbot/dist-in/iterator.js @@ -1,6 +1,11 @@ import { defaultError, defaultFilters, testFilters, transformObjectWithOptions } from './async-iterator.js'; import { run } from './commands/run.js'; import { get_cached_object, set_cached_object } from "@polymech/cache"; +const dummyLogger = { + info: () => { }, + warn: () => { }, + error: () => { } +}; export const removeEmptyObjects = (obj) => { if (obj === null || obj === undefined) return obj; @@ -23,14 +28,12 @@ const DEFAULT_CACHE_CONFIG = { namespace: 'llm-responses', expiration: 7 * 24 * 60 * 60 // 7 days in seconds }; -export function createLLMTransformer(options, logger, cacheConfig) { +export function createLLMTransformer(options, logger = dummyLogger, cacheConfig) { const config = { ...DEFAULT_CACHE_CONFIG, ...cacheConfig }; return async (input, jsonPath) => { - if (logger) { - logger.info(`Transforming field at path: ${jsonPath}`); - logger.info(`Input: ${input}`); - logger.info(`Using prompt: ${options.prompt}`); - } + logger.info(`Transforming field at path: ${jsonPath}`); + logger.info(`Input: ${input}`); + logger.info(`Using prompt: ${options.prompt}`); const kbotTask = { ...options, prompt: `${options.prompt}\n\nText to transform: "${input}"`, @@ -47,8 +50,7 @@ export function createLLMTransformer(options, logger, cacheConfig) { if (config.enabled) { const cachedResponse = await get_cached_object({ ca_options: cacheKeyObj }, config.namespace); if (cachedResponse?.content) { - if (logger) - logger.info(`Using cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`); + logger.info(`Using cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`); return cachedResponse.content; } } @@ -57,42 +59,73 @@ export function createLLMTransformer(options, logger, cacheConfig) { const result = results[0].trim(); if (config.enabled) { await set_cached_object({ ca_options: cacheKeyObj }, config.namespace, { content: result }, { expiration: config.expiration }); - if (logger) - logger.info(`Cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`); + logger.info(`Cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`); } - if (logger) - logger.info(`Result: ${result}`); + logger.info(`Result: ${result}`); return result; } - if (logger) - logger.warn(`No valid result received for ${jsonPath}, returning original`); + logger.warn(`No valid result received for ${jsonPath}, returning original`); return input; } catch (error) { - if (logger) { - logger.error(`Error calling LLM API: ${error.message}`, error); - } - else { - console.error(`Error calling LLM API: ${error.message}`, error); - } + logger.error(`Error calling LLM API: ${error.message}`, error); return input; } }; } export function createIterator(obj, optionsMixin, globalOptions = {}) { - const { throttleDelay = 1000, concurrentTasks = 1, errorCallback = defaultError, filterCallback = testFilters(defaultFilters()), transformerFactory, maxRetries = 3, retryDelay = 2000, logger, cacheConfig } = globalOptions; + const { throttleDelay = 1000, concurrentTasks = 1, errorCallback = defaultError, filterCallback = testFilters(defaultFilters()), transformerFactory, maxRetries = 3, retryDelay = 2000, logger = dummyLogger, cacheConfig } = globalOptions; + const config = { ...DEFAULT_CACHE_CONFIG, ...cacheConfig }; const defaultTransformerFactory = (options) => { return async (input) => input; }; const createTransformer = transformerFactory || defaultTransformerFactory; + const createObjectCacheKey = (data, mappings) => { + return removeEmptyObjects({ + data: JSON.stringify(data), + mappings: mappings.map(m => ({ + jsonPath: m.jsonPath, + targetPath: m.targetPath, + options: { + model: optionsMixin.model, + router: optionsMixin.router, + mode: optionsMixin.mode, + prompt: m.options?.prompt + } + })) + }); + }; + const deepMerge = (target, source) => { + for (const key in source) { + if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) { + if (!target[key]) + target[key] = {}; + deepMerge(target[key], source[key]); + } + else { + target[key] = source[key]; + } + } + }; return { createTransformer, transform: async (mappings) => { + if (config.enabled) { + const objectCacheKey = createObjectCacheKey(obj, mappings); + const cachedObject = await get_cached_object({ ca_options: objectCacheKey }, 'transformed-objects'); + if (cachedObject?.content) { + logger.info('Using cached transformed object'); + deepMerge(obj, cachedObject.content); + return; + } + } + // If no cache hit or caching disabled, perform the transformations + const transformedObj = JSON.parse(JSON.stringify(obj)); for (const mapping of mappings) { const mergedOptions = { ...optionsMixin, ...mapping.options }; const { jsonPath, targetPath = null, maxRetries: mappingRetries, retryDelay: mappingRetryDelay } = mapping; const transformer = createTransformer(mergedOptions); - await transformObjectWithOptions(obj, transformer, { + await transformObjectWithOptions(transformedObj, transformer, { jsonPath, targetPath, throttleDelay, @@ -103,6 +136,14 @@ export function createIterator(obj, optionsMixin, globalOptions = {}) { retryDelay: mappingRetryDelay || retryDelay }); } + // Cache the transformed object + if (config.enabled) { + const objectCacheKey = createObjectCacheKey(obj, mappings); + await set_cached_object({ ca_options: objectCacheKey }, 'transformed-objects', { content: transformedObj }, { expiration: config.expiration }); + logger.info('Cached transformed object'); + } + // Apply the transformations to the original object + deepMerge(obj, transformedObj); } }; } @@ -110,4 +151,4 @@ export async function transformWithMappings(obj, createTransformer, mappings, gl const iterator = createIterator(obj, {}, globalOptions); await iterator.transform(mappings); } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXRlcmF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaXRlcmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFtRCxZQUFZLEVBQUUsY0FBYyxFQUFFLFdBQVcsRUFBRSwwQkFBMEIsRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQzVKLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUN2QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsaUJBQWlCLEVBQW9CLE1BQU0saUJBQWlCLENBQUE7QUFFeEYsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxHQUFRLEVBQU8sRUFBRTtJQUNoRCxJQUFJLEdBQUcsS0FBSyxJQUFJLElBQUksR0FBRyxLQUFLLFNBQVM7UUFBRSxPQUFPLEdBQUcsQ0FBQztJQUNsRCxLQUFLLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ3BCLE1BQU0sR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUNwQixJQUFJLEdBQUcsS0FBSyxJQUFJLElBQUksR0FBRyxLQUFLLFNBQVM7WUFBRSxTQUFTO1FBQ2hELElBQUksT0FBTyxHQUFHLEtBQUssUUFBUTtZQUN2QixDQUFDLEdBQUcsSUFBSSxPQUFPLElBQUksT0FBTyxHQUFHLEtBQUssUUFBUSxJQUFJLEdBQUcsS0FBSyxDQUFDLElBQUksR0FBRyxJQUFJLFFBQVEsQ0FBQyxFQUM3RSxDQUFDO1lBQ0MsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ3hDLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQ3JDLE9BQU8sR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ3BCLENBQUM7UUFDTCxDQUFDO0lB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 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXRlcmF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaXRlcmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFtRCxZQUFZLEVBQUUsY0FBYyxFQUFFLFdBQVcsRUFBRSwwQkFBMEIsRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQzVKLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUN2QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsaUJBQWlCLEVBQW9CLE1BQU0saUJBQWlCLENBQUE7QUFTeEYsTUFBTSxXQUFXLEdBQVk7SUFDekIsSUFBSSxFQUFFLEdBQUcsRUFBRSxHQUFFLENBQUM7SUFDZCxJQUFJLEVBQUUsR0FBRyxFQUFFLEdBQUUsQ0FBQztJQUNkLEtBQUssRUFBRSxHQUFHLEVBQUUsR0FBRSxDQUFDO0NBQ2xCLENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyxDQUFDLEdBQVEsRUFBTyxFQUFFO0lBQ2hELElBQUksR0FBRyxLQUFLLElBQUksSUFBSSxHQUFHLEtBQUssU0FBUztRQUFFLE9BQU8sR0FBRyxDQUFDO0lBQ2xELEtBQUssTUFBTSxHQUFHLElBQUksR0FBRyxFQUFFLENBQUM7UUFDcEIsTUFBTSxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1FBQ3BCLElBQUksR0FBRyxLQUFLLElBQUksSUFBSSxHQUFHLEtBQUssU0FBUztZQUFFLFNBQVM7UUFDaEQsSUFBSSxPQUFPLEdBQUcsS0FBSyxRQUFRO1lBQ3ZCLENBQUMsR0FBRyxJQUFJLE9BQU8sSUFBSSxPQUFPLEdBQUcsS0FBSyxRQUFRLElBQUksR0FBRyxLQUFLLENBQUMsSUFBSSxHQUFHLElBQUksUUFBUSxDQUFDLEVBQzdFLENBQUM7WUFDQyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsa0JBQWtCLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDeEMsSUFB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 \ No newline at end of file diff --git a/packages/kbot/src/examples/core/iterator-factory-example.ts b/packages/kbot/src/examples/core/iterator-factory-example.ts index d773caf3..a51dac5e 100644 --- a/packages/kbot/src/examples/core/iterator-factory-example.ts +++ b/packages/kbot/src/examples/core/iterator-factory-example.ts @@ -49,21 +49,21 @@ const exampleData = { // Field mappings definition const fieldMappings: FieldMapping[] = [ { - jsonPath: '$..description', + jsonPath: '$.products.fruits[*].description', targetPath: null, options: { prompt: 'Make this description more engaging and detailed, around 20-30 words' } }, { - jsonPath: '$..nutrition', + jsonPath: '$.products.fruits[*].details.nutrition', targetPath: null, options: { prompt: 'Expand this nutrition information with 2-3 specific health benefits, around 25-35 words' } }, { - jsonPath: '$..name', + jsonPath: '$.products.fruits[*].name', targetPath: 'marketingName', options: { prompt: 'Generate a more appealing marketing name for this product' @@ -89,17 +89,6 @@ export async function factoryExample() { console.log("========================================"); try { - // Clear the test-data folder - const outputPath = path.resolve('./tests/test-data/core/iterator-factory-data.json'); - const outputDir = path.dirname(outputPath); - if (!fs.existsSync(outputDir)) { - fs.mkdirSync(outputDir, { recursive: true }); - } - // Make sure the file is empty to start with a clean slate - if (fs.existsSync(outputPath)) { - fs.unlinkSync(outputPath); - } - const data = JSON.parse(JSON.stringify(exampleData)); // Global options for all transformations @@ -120,7 +109,7 @@ export async function factoryExample() { errorCallback, filterCallback: async () => true, transformerFactory: (options) => createLLMTransformer(options, logger, cacheConfig), - logger: logger, + logger, cacheConfig } ); @@ -129,15 +118,25 @@ export async function factoryExample() { console.log("First run - should transform and cache results:"); await iterator.transform(fieldMappings); + const outputPath = path.resolve('./tests/test-data/core/iterator-factory-data.json'); + const outputDir = path.dirname(outputPath); + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + // Make sure the file is empty to start with a clean slate + if (fs.existsSync(outputPath)) { + fs.unlinkSync(outputPath); + } + write(outputPath, JSON.stringify(data, null, 2)); console.log("Transformation complete. Results saved to", outputPath); // Print the transformed data structure console.log("\nTransformed data structure:"); - console.log(JSON.stringify(data.products.fruits[0], null, 2).substring(0, 200) + "..."); + console.log(JSON.stringify(data.products.fruits[0], null, 2)); // Create a second instance with the same data to test cache - console.log("\n\n========================================"); + console.log("\n========================================"); console.log("Second run - should use cached results:"); console.log("========================================"); @@ -152,7 +151,7 @@ export async function factoryExample() { errorCallback, filterCallback: async () => true, transformerFactory: (options) => createLLMTransformer(options, logger, cacheConfig), - logger: logger, + logger, cacheConfig } ); @@ -162,13 +161,9 @@ export async function factoryExample() { console.log("\nBefore/After Comparison Example:"); console.log(`Original description: ${exampleData.products.fruits[0].description}`); - console.log(`Transformed description: ${data.products.fruits[0].description}`); + console.log(`Transformed description: ${data2.products.fruits[0].description}`); console.log(`Original name: ${exampleData.products.fruits[0].name}`); - - // Check if name is an object with marketingName property - const name = data.products.fruits[0].name; - const marketingName = typeof name === 'object' && name !== null ? name.marketingName : 'Not available'; - console.log(`New marketing name: ${marketingName}`); + console.log(`Marketing name: ${data2.products.fruits[0].marketingName || 'Not available'}`); return data; } catch (error) { diff --git a/packages/kbot/src/iterator.ts b/packages/kbot/src/iterator.ts index 7827af2a..f850b1ee 100644 --- a/packages/kbot/src/iterator.ts +++ b/packages/kbot/src/iterator.ts @@ -2,6 +2,19 @@ import { IKBotTask } from '@polymech/ai-tools' import { AsyncTransformer, ErrorCallback, FilterCallback, defaultError, defaultFilters, testFilters, transformObjectWithOptions } from './async-iterator.js' import { run } from './commands/run.js' import { get_cached_object, set_cached_object, rm_cached_object } from "@polymech/cache" +import { deepClone } from "@polymech/core/objects" + +export interface ILogger { + info: (message: string) => void; + warn: (message: string) => void; + error: (message: string, error?: any) => void; +} + +const dummyLogger: ILogger = { + info: () => {}, + warn: () => {}, + error: () => {} +}; export const removeEmptyObjects = (obj: any): any => { if (obj === null || obj === undefined) return obj; @@ -39,6 +52,18 @@ export interface CacheConfig { expiration?: number; // in seconds } +export interface IOptions { + throttleDelay?: number; + concurrentTasks?: number; + errorCallback?: ErrorCallback; + filterCallback?: FilterCallback; + transformerFactory?: (options: IKBotTask) => AsyncTransformer; + maxRetries?: number; + retryDelay?: number; + logger?: ILogger; + cacheConfig?: CacheConfig; +} + const DEFAULT_CACHE_CONFIG: Required = { enabled: true, namespace: 'llm-responses', @@ -47,21 +72,15 @@ const DEFAULT_CACHE_CONFIG: Required = { export function createLLMTransformer( options: IKBotTask, - logger?: { - info: (message: string) => void; - warn: (message: string) => void; - error: (message: string, error?: any) => void; - }, + logger: ILogger = dummyLogger, cacheConfig?: CacheConfig ): AsyncTransformer { const config: Required = { ...DEFAULT_CACHE_CONFIG, ...cacheConfig }; return async (input: string, jsonPath: string): Promise => { - if (logger) { - logger.info(`Transforming field at path: ${jsonPath}`); - logger.info(`Input: ${input}`); - logger.info(`Using prompt: ${options.prompt}`); - } + logger.info(`Transforming field at path: ${jsonPath}`); + logger.info(`Input: ${input}`); + logger.info(`Using prompt: ${options.prompt}`); const kbotTask: IKBotTask = { ...options, @@ -81,7 +100,7 @@ export function createLLMTransformer( if (config.enabled) { const cachedResponse = await get_cached_object({ ca_options: cacheKeyObj }, config.namespace) as { content: string }; if (cachedResponse?.content) { - if (logger) logger.info(`Using cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`); + logger.info(`Using cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`); return cachedResponse.content; } } @@ -97,21 +116,17 @@ export function createLLMTransformer( { content: result }, { expiration: config.expiration } ); - if (logger) logger.info(`Cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`); + logger.info(`Cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`); } - if (logger) logger.info(`Result: ${result}`); + logger.info(`Result: ${result}`); return result; } - if (logger) logger.warn(`No valid result received for ${jsonPath}, returning original`); + logger.warn(`No valid result received for ${jsonPath}, returning original`); return input; } catch (error) { - if (logger) { - logger.error(`Error calling LLM API: ${error.message}`, error); - } else { - console.error(`Error calling LLM API: ${error.message}`, error); - } + logger.error(`Error calling LLM API: ${error.message}`, error); return input; } }; @@ -120,17 +135,7 @@ export function createLLMTransformer( export function createIterator( obj: Record, optionsMixin: Partial, - globalOptions: { - throttleDelay?: number - concurrentTasks?: number - errorCallback?: ErrorCallback - filterCallback?: FilterCallback - transformerFactory?: (options: IKBotTask) => AsyncTransformer - maxRetries?: number - retryDelay?: number - logger?: { error: (message: string, error?: any) => void } - cacheConfig?: CacheConfig - } = {} + globalOptions: IOptions = {} ): IteratorFactory { const { throttleDelay = 1000, @@ -140,26 +145,71 @@ export function createIterator( transformerFactory, maxRetries = 3, retryDelay = 2000, - logger, + logger = dummyLogger, cacheConfig } = globalOptions; + const config: Required = { ...DEFAULT_CACHE_CONFIG, ...cacheConfig }; + const defaultTransformerFactory = (options: IKBotTask): AsyncTransformer => { return async (input: string): Promise => input; }; const createTransformer = transformerFactory || defaultTransformerFactory; + const createObjectCacheKey = (data: Record, mappings: FieldMapping[]) => { + return removeEmptyObjects({ + data: JSON.stringify(data), + mappings: mappings.map(m => ({ + jsonPath: m.jsonPath, + targetPath: m.targetPath, + options: { + model: optionsMixin.model, + router: optionsMixin.router, + mode: optionsMixin.mode, + prompt: m.options?.prompt + } + })) + }); + }; + + const deepMerge = (target: Record, source: Record) => { + for (const key in source) { + if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) { + if (!target[key]) target[key] = {}; + deepMerge(target[key], source[key]); + } else { + target[key] = source[key]; + } + } + }; + return { createTransformer, transform: async (mappings: FieldMapping[]): Promise => { + if (config.enabled) { + const objectCacheKey = createObjectCacheKey(obj, mappings); + const cachedObject = await get_cached_object( + { ca_options: objectCacheKey }, + 'transformed-objects' + ) as { content: Record }; + + if (cachedObject?.content) { + logger.info('Using cached transformed object'); + deepMerge(obj, cachedObject.content); + return; + } + } + + // If no cache hit or caching disabled, perform the transformations + const transformedObj = JSON.parse(JSON.stringify(obj)); for (const mapping of mappings) { const mergedOptions = { ...optionsMixin, ...mapping.options } as IKBotTask; const { jsonPath, targetPath = null, maxRetries: mappingRetries, retryDelay: mappingRetryDelay } = mapping; const transformer = createTransformer(mergedOptions); await transformObjectWithOptions( - obj, + transformedObj, transformer, { jsonPath, @@ -173,6 +223,21 @@ export function createIterator( } ); } + + // Cache the transformed object + if (config.enabled) { + const objectCacheKey = createObjectCacheKey(obj, mappings); + await set_cached_object( + { ca_options: objectCacheKey }, + 'transformed-objects', + { content: transformedObj }, + { expiration: config.expiration } + ); + logger.info('Cached transformed object'); + } + + // Apply the transformations to the original object + deepMerge(obj, transformedObj); } }; }