diff --git a/packages/kbot/.vscode/launch.json b/packages/kbot/.vscode/launch.json index ffa00c01..84d72409 100644 --- a/packages/kbot/.vscode/launch.json +++ b/packages/kbot/.vscode/launch.json @@ -723,6 +723,24 @@ "!**/node_modules/**" ], "outputCapture": "std" + }, + { + "type": "node", + "request": "launch", + "name": "examples:iterator-factory", + "skipFiles": ["/**"], + "cwd": "${workspaceFolder}", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "examples:iterator-factory"], + "outFiles": ["${workspaceFolder}/**/*.js", "${workspaceFolder}/**/*.ts"], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "sourceMaps": true, + "resolveSourceMapLocations": [ + "${workspaceFolder}/**", + "!**/node_modules/**" + ], + "outputCapture": "std" } ] } \ No newline at end of file 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 efdffc23..780716de 100644 --- a/packages/kbot/dist-in/examples/core/iterator-factory-example.js +++ b/packages/kbot/dist-in/examples/core/iterator-factory-example.js @@ -3,35 +3,7 @@ import * as path from 'path'; import * as fs from 'fs'; import { E_OPENROUTER_MODEL } from '../../models/cache/openrouter-models.js'; import { E_Mode } from '../../zod_schema.js'; -import { createIterator, registerCacheModule } from '../../iterator.js'; -import { run } from '../../commands/run.js'; -// Clear the mock cache for fresh testing -const mockCacheModule = { - _cache: new Map(), - get_cached_object: async (key, namespace) => { - const cacheKey = JSON.stringify({ key, namespace }); - console.log(`Cache: Looking up ${cacheKey}`); - return mockCacheModule._cache.get(cacheKey) || null; - }, - set_cached_object: async (key, namespace, value) => { - const cacheKey = JSON.stringify({ key, namespace }); - console.log(`Cache: Storing in ${cacheKey}`); - mockCacheModule._cache.set(cacheKey, value); - // Show what's being stored for debugging - console.log(`Cache value stored: ${JSON.stringify(value, null, 2).substring(0, 100)}...`); - }, - rm_cached_object: async (key, namespace) => { - const cacheKey = JSON.stringify({ key, namespace }); - console.log(`Cache: REMOVING ${cacheKey}`); - // Check if it existed before removal - const existed = mockCacheModule._cache.has(cacheKey); - mockCacheModule._cache.delete(cacheKey); - // Show removal status - console.log(`Cache removal: ${existed ? 'REMOVED EXISTING CACHE VALUE' : 'NO CACHE VALUE FOUND'}`); - } -}; -// Register our mock cache module -registerCacheModule(mockCacheModule); +import { createIterator, createLLMTransformer } from '../../iterator.js'; const MODEL = E_OPENROUTER_MODEL.MODEL_OPENROUTER_QUASAR_ALPHA; const ROUTER = 'openrouter'; const LOG_LEVEL = 2; @@ -93,32 +65,6 @@ const fieldMappings = [ } } ]; -// Create LLM transformer factory -const createLLMTransformer = (options) => { - return async (input, jsonPath) => { - 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}"`, - }; - try { - const results = await run(kbotTask); - if (results && results.length > 0 && typeof results[0] === 'string') { - const result = results[0].trim(); - logger.info(`Result: ${result}`); - return result; - } - logger.warn(`No valid result received for ${jsonPath}, returning original`); - return input; - } - catch (error) { - console.error(`Error calling LLM API: ${error.message}`, error); - return input; - } - }; -}; // Error handler const errorCallback = (path, value, error) => { logger.error(`Error transforming ${path}: ${error.message}`); @@ -152,7 +98,7 @@ export async function factoryExample() { concurrentTasks: 1, errorCallback, filterCallback: async () => true, - transformerFactory: createLLMTransformer, + transformerFactory: (options) => createLLMTransformer(options, logger), logger: logger, cache: { enabled: true, @@ -177,7 +123,7 @@ export async function factoryExample() { concurrentTasks: 1, errorCallback, filterCallback: async () => true, - transformerFactory: createLLMTransformer, + transformerFactory: (options) => createLLMTransformer(options, logger), logger: logger, cache: { enabled: true, @@ -186,55 +132,6 @@ export async function factoryExample() { }); // Should use cached values await iterator2.transform(fieldMappings); - // Manually set the marketingName for demonstration purposes - data2.products.fruits[0].name = { - value: "apple", - marketingName: "Crimson Orchard Delight" - }; - data2.products.fruits[1].name = { - value: "banana", - marketingName: "Golden Delight Banana" - }; - // Now create a third instance with caching disabled to demonstrate cache cleanup - console.log("\n\n========================================"); - console.log("Third run - with caching disabled (should clean up cache):"); - console.log("========================================"); - /* - const data3 = JSON.parse(JSON.stringify(exampleData)); - - const iterator3 = createIterator( - data3, - globalOptionsMixin, - { - throttleDelay: 1000, - concurrentTasks: 1, - errorCallback, - filterCallback: async () => true, - transformerFactory: createLLMTransformer, - logger: logger, - cache: { - enabled: false, // Caching disabled - namespace: 'product-transformations' - } - } - ); - - // Should transform again and remove the cache - await iterator3.transform(fieldMappings); - - // Verify cache was removed by checking if it still exists - console.log("\nVerifying cache removal:"); - const cacheKey = { - key: JSON.stringify({ - jsonPath: '$..name', - targetPath: 'marketingName', - options: { ...globalOptionsMixin, prompt: 'Generate a more appealing marketing name for this product' } - }), - name: 'product-transformations' - }; - const cachedValue = await mockCacheModule.get_cached_object(cacheKey, 'product-transformations'); - console.log(`Cache still exists? ${cachedValue !== null ? 'Yes' : 'No'}`); - */ console.log("\nBefore/After Comparison Example:"); console.log(`Original description: ${exampleData.products.fruits[0].description}`); console.log(`Transformed description: ${data.products.fruits[0].description}`); @@ -250,22 +147,16 @@ export async function factoryExample() { throw error; } } -console.log("Module loading, checking if this is direct execution"); -console.log("process.argv[1]:", process.argv[1]); -console.log("import.meta.url:", import.meta.url); -const isDirectExecution = process.argv[1] && process.argv[1].includes('iterator-factory-example'); -console.log("Is direct execution:", isDirectExecution); -if (isDirectExecution) { +if (process.argv[1] && process.argv[1].includes('iterator-factory-example')) { const isDebug = process.argv.includes('--debug'); console.log('Starting iterator factory example...'); console.log(`Command arguments: ${process.argv.slice(2).join(', ')}`); console.log(`Debug mode: ${isDebug ? 'enabled' : 'disabled'}`); if (isDebug) { - // Set up debug logging console.log("Running in debug mode with verbose output"); } factoryExample().catch(error => { console.error("Unhandled error:", error); }); } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXRlcmF0b3ItZmFjdG9yeS1leGFtcGxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2V4YW1wbGVzL2NvcmUvaXRlcmF0b3ItZmFjdG9yeS1leGFtcGxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxJQUFJLElBQUksS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbkQsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFFekIsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDN0UsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRTdDLE9BQU8sRUFBZ0IsY0FBYyxFQUFnQixtQkFBbUIsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3BHLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUU1Qyx5Q0FBeUM7QUFDekMsTUFBTSxlQUFlLEdBQUc7SUFDcEIsTUFBTSxFQUFFLElBQUksR0FBRyxFQUFlO0lBQzlCLGlCQUFpQixFQUFFLEtBQUssRUFBRSxHQUFRLEVBQUUsU0FBaUIsRUFBRSxFQUFFO1FBQ3JELE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztRQUNwRCxPQUFPLENBQUMsR0FBRyxDQUFDLHFCQUFxQixRQUFRLEVBQUUsQ0FBQyxDQUFDO1FBQzdDLE9BQU8sZUFBZSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLElBQUksSUFBSSxDQUFDO0lBQ3hELENBQUM7SUFDRCxpQkFBaUIsRUFBRSxLQUFLLEVBQUUsR0FBUSxFQUFFLFNBQWlCLEVBQUUsS0FBVSxFQUFFLEVBQUU7UUFDakUsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxF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 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXRlcmF0b3ItZmFjdG9yeS1leGFtcGxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2V4YW1wbGVzL2NvcmUvaXRlcmF0b3ItZmFjdG9yeS1leGFtcGxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxJQUFJLElBQUksS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbkQsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFFekIsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDN0UsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRTdDLE9BQU8sRUFBZ0IsY0FBYyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFdkYsTUFBTSxLQUFLLEdBQUcsa0JBQWtCLENBQUMsNkJBQTZCLENBQUM7QUFDL0QsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDO0FBQzVCLE1BQU0sU0FBUyxHQUFHLENBQUMsQ0FBQztBQUVwQixNQUFNLE1BQU0sR0FBRztJQUNYLElBQUksRUFBRSxDQUFDLE9BQWUsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLE9BQU8sRUFBRSxDQUFDO0lBQzFELElBQUksRUFBRSxDQUFDLE9BQWUsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLE9BQU8sRUFBRSxDQUFDO0lBQzFELEtBQUssRUFBRSxDQUFDLE9BQWUsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxVQUFVLE9BQU8sRUFBRSxDQUFDO0lBQzlELEtBQUssRUFBRSxDQUFDLE9BQWUsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLE9BQU8sRUFBRSxDQUFDO0lBQzVELEtBQUssRUFBRSxDQUFDLE9B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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 03a4908e..29eb3673 100644 --- a/packages/kbot/dist-in/iterator.d.ts +++ b/packages/kbot/dist-in/iterator.d.ts @@ -1,35 +1,6 @@ import { IKBotTask } from '@polymech/ai-tools'; import { AsyncTransformer, ErrorCallback, FilterCallback } from './async-iterator.js'; -declare let cacheModule: { - get_cached_object: (key: any, namespace: string) => Promise; - set_cached_object: (key: any, namespace: string, value: any, options?: any) => Promise; - rm_cached_object: (key: any, namespace: string) => Promise; -} | null; -export declare function registerCacheModule(module: typeof cacheModule): void; -export interface CacheInterface { - get: (key: any) => Promise; - set: (key: any, value: any) => Promise; - delete?: (key: any) => Promise; -} -export declare class NoopCache implements CacheInterface { - get(_key: any): Promise; - set(_key: any, _value: any): Promise; - delete(_key: any): Promise; -} -export declare class DefaultCache implements CacheInterface { - private readonly logger?; - constructor(logger?: { - error: (message: string, error?: any) => void; - }); - get(key: any): Promise; - set(key: any, value: any): Promise; - delete(key: any): Promise; -} -export interface CacheOptions { - enabled: boolean; - implementation?: CacheInterface; - namespace?: string; -} +export declare const removeEmptyObjects: (obj: any) => any; export interface FieldMapping { jsonPath: string; targetPath?: string | null; @@ -41,8 +12,11 @@ export interface IteratorFactory { transform: (mappings: FieldMapping[]) => Promise; createTransformer: (options: IKBotTask) => AsyncTransformer; } -export declare function createCacheKey(obj: any): string; -export declare function removeEmptyValues(obj: any): any; +export declare function createLLMTransformer(options: IKBotTask, logger?: { + info: (message: string) => void; + warn: (message: string) => void; + error: (message: string, error?: any) => void; +}): AsyncTransformer; export declare function createIterator(obj: Record, optionsMixin: Partial, globalOptions?: { throttleDelay?: number; concurrentTasks?: number; @@ -51,7 +25,6 @@ export declare function createIterator(obj: Record, optionsMixin: P transformerFactory?: (options: IKBotTask) => AsyncTransformer; maxRetries?: number; retryDelay?: number; - cache?: CacheOptions; logger?: { error: (message: string, error?: any) => void; }; @@ -63,9 +36,7 @@ export declare function transformWithMappings(obj: Record, createTr filterCallback?: FilterCallback; maxRetries?: number; retryDelay?: number; - cache?: CacheOptions; logger?: { error: (message: string, error?: any) => void; }; }): Promise; -export {}; diff --git a/packages/kbot/dist-in/iterator.js b/packages/kbot/dist-in/iterator.js index d02633ba..2c216aad 100644 --- a/packages/kbot/dist-in/iterator.js +++ b/packages/kbot/dist-in/iterator.js @@ -1,335 +1,106 @@ import { defaultError, defaultFilters, testFilters, transformObjectWithOptions } from './async-iterator.js'; -import { JSONPath } from 'jsonpath-plus'; -// Add an optional import that can be provided by the user -let cacheModule = null; -// Function to register the cache module -export function registerCacheModule(module) { - cacheModule = module; -} -// Default no-op cache implementation -export class NoopCache { - async get(_key) { return null; } - async set(_key, _value) { return; } - async delete(_key) { return; } -} -// Default cache implementation based on kbot.ts pattern -export class DefaultCache { - logger; - constructor(logger) { - this.logger = logger; - } - async get(key) { - if (!cacheModule) - return null; - try { - const namespace = key.name || 'iterator'; - const cached = await cacheModule.get_cached_object(key, namespace); - return cached; - } - catch (e) { - if (this.logger) { - this.logger.error(`Failed to get cached object for key: ${JSON.stringify(key).substring(0, 50)}`, e); - } - else { - console.error(`Cache get error:`, e); - } - return null; - } - } - async set(key, value) { - if (!cacheModule) - return; - try { - const namespace = key.name || 'iterator'; - await cacheModule.set_cached_object(key, namespace, value, {}); - } - catch (e) { - if (this.logger) { - this.logger.error(`Failed to cache object for key: ${JSON.stringify(key).substring(0, 50)}`, e); - } - else { - console.error(`Cache set error:`, e); - } - } - } - async delete(key) { - if (!cacheModule) - return; - try { - const namespace = key.name || 'iterator'; - await cacheModule.rm_cached_object(key, namespace); - } - catch (e) { - if (this.logger) { - this.logger.error(`Failed to delete cached object for key: ${JSON.stringify(key).substring(0, 50)}`, e); - } - else { - console.error(`Cache delete error:`, e); - } - } - } -} -// Utility function to create a cache key from an object -export function createCacheKey(obj) { - try { - const cleanObj = JSON.parse(JSON.stringify(removeEmptyValues(obj))); - return JSON.stringify(cleanObj); - } - catch (e) { - console.error("Error creating cache key:", e); - // Fallback to simpler stringification if error occurs - return JSON.stringify({ hash: String(Date.now()) }); - } -} -// Utility to remove null, undefined, and empty objects from an object for cache key generation -export function removeEmptyValues(obj) { - if (obj === null || obj === undefined) { - return undefined; - } - if (typeof obj !== 'object') { +import { run } from './commands/run.js'; +import { get_cached_object, set_cached_object } from "@polymech/cache"; +export const removeEmptyObjects = (obj) => { + if (obj === null || obj === undefined) return obj; - } - if (Array.isArray(obj)) { - const filtered = obj.map(removeEmptyValues).filter(v => v !== undefined); - return filtered.length ? filtered : undefined; - } - const result = {}; - let hasValues = false; - for (const [key, value] of Object.entries(obj)) { - const cleaned = removeEmptyValues(value); - if (cleaned !== undefined) { - result[key] = cleaned; - hasValues = true; + for (const key in obj) { + const val = obj[key]; + if (val === null || val === undefined) + continue; + if (typeof val === 'object' || + (key == 'value' && typeof val === 'number' && val === 0 || key == 'base64')) { + obj[key] = removeEmptyObjects(obj[key]); + if (Object.keys(obj[key]).length === 0) { + delete obj[key]; + } } } - return hasValues ? result : undefined; + return obj; +}; +export function createLLMTransformer(options, logger) { + return async (input, jsonPath) => { + if (logger) { + 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}"`, + }; + // Create cache key for the LLM call + const cacheKeyObj = removeEmptyObjects({ + prompt: kbotTask.prompt, + model: kbotTask.model, + router: kbotTask.router, + mode: kbotTask.mode, + filters: [], + tools: [] + }); + try { + const cachedResponse = await get_cached_object({ ca_options: cacheKeyObj }, 'llm-responses'); + if (cachedResponse?.content) { + if (logger) + logger.info(`Using cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`); + return cachedResponse.content; + } + const results = await run(kbotTask); + if (results && results.length > 0 && typeof results[0] === 'string') { + const result = results[0].trim(); + await set_cached_object({ ca_options: cacheKeyObj }, 'llm-responses', { content: result }, {}); + if (logger) + logger.info(`Cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`); + if (logger) + logger.info(`Result: ${result}`); + return result; + } + if (logger) + 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); + } + return input; + } + }; } export function createIterator(obj, optionsMixin, globalOptions = {}) { - const { throttleDelay = 1000, concurrentTasks = 1, errorCallback = defaultError, filterCallback = testFilters(defaultFilters()), transformerFactory, maxRetries = 3, retryDelay = 2000, cache, logger } = globalOptions; + const { throttleDelay = 1000, concurrentTasks = 1, errorCallback = defaultError, filterCallback = testFilters(defaultFilters()), transformerFactory, maxRetries = 3, retryDelay = 2000, logger } = globalOptions; const defaultTransformerFactory = (options) => { // This is a placeholder transformer that just returns the input // In real usage, this would be replaced by the provided transformerFactory return async (input) => input; }; const createTransformer = transformerFactory || defaultTransformerFactory; - // Default cache settings - const defaultImplementation = logger ? new DefaultCache(logger) : new DefaultCache(); - const cacheImpl = cache?.implementation || defaultImplementation; - const cacheEnabled = cache?.enabled || false; - const cacheNamespace = cache?.namespace || 'iterator'; return { createTransformer, transform: async (mappings) => { for (const mapping of mappings) { - // Merge the mapping options with the global mixin const mergedOptions = { ...optionsMixin, ...mapping.options }; const { jsonPath, targetPath = null, maxRetries: mappingRetries, retryDelay: mappingRetryDelay } = mapping; const transformer = createTransformer(mergedOptions); - // Generate cache key for this transformation - if (cacheEnabled) { - const cacheKeyObj = { - jsonPath, - targetPath, - options: mergedOptions, - maxRetries: mappingRetries || maxRetries, - retryDelay: mappingRetryDelay || retryDelay - }; - const cacheKey = { key: createCacheKey(cacheKeyObj), name: cacheNamespace }; - // Check if we have a cached result - try { - const cachedResult = await cacheImpl.get(cacheKey); - if (cachedResult) { - // Apply cached result directly - applyTransformResult(obj, jsonPath, targetPath, cachedResult); - continue; // Skip to next mapping - } - } - catch (e) { - errorCallback('cache', 'get', e); - } - // For paths with targetPath, we need special handling for the LLM results - if (targetPath) { - // Get all the values that need transformation - const paths = JSONPath({ path: jsonPath, json: obj, resultType: 'pointer' }); - const transformedData = {}; - for (const path of paths) { - // Extract the value to transform - const keys = path.slice(1).split('/'); - let current = obj; - for (const key of keys) { - if (key === '') - continue; - if (current === undefined || current === null) - break; - current = current[key]; - } - // Transform the value if it exists - if (current !== undefined) { - try { - // Perform the transformation using the LLM - const rawValue = typeof current === 'object' && current !== null && 'value' in current - ? current.value - : current; - const result = await transformer(String(rawValue), path); - // Store the result with the target path - transformedData[path] = { [targetPath]: result }; - } - catch (e) { - errorCallback(path, String(current), e); - } - } - } - // Store the result in the cache - if (Object.keys(transformedData).length > 0) { - try { - await cacheImpl.set(cacheKey, transformedData); - } - catch (e) { - errorCallback('cache', 'set', e); - } - // Apply the transformations - applyTransformResult(obj, jsonPath, targetPath, transformedData); - } - } - else { - // Regular case without targetPath - use normal approach - // Create a deep clone to transform - const objCopy = JSON.parse(JSON.stringify(obj)); - // Perform the transformation - await transformObjectWithOptions(objCopy, transformer, { - jsonPath, - targetPath, - throttleDelay, - concurrentTasks, - errorCallback, - filterCallback, - maxRetries: mappingRetries || maxRetries, - retryDelay: mappingRetryDelay || retryDelay - }); - // Store the result in the cache - try { - // Extract the transformed parts to store in cache - const transformedData = extractTransformedData(objCopy, jsonPath, targetPath); - await cacheImpl.set(cacheKey, transformedData); - } - catch (e) { - errorCallback('cache', 'set', e); - } - // Apply the transformation to the original object - applyTransformResult(obj, jsonPath, targetPath, extractTransformedData(objCopy, jsonPath, targetPath)); - } - } - else { - // Caching is disabled, but check if there are old cached values that should be removed - try { - // Create the same cacheKeyObj as used when caching is enabled - const keyObj = { - jsonPath, - targetPath, - options: mergedOptions, - maxRetries: mappingRetries || maxRetries, - retryDelay: mappingRetryDelay || retryDelay - }; - const cacheKey = { key: createCacheKey(keyObj), name: cacheNamespace }; - const cachedResult = await cacheImpl.get(cacheKey); - if (cachedResult && cacheImpl.delete) { - // If item exists in cache but caching is disabled, remove it - await cacheImpl.delete(cacheKey); - } - } - catch (e) { - // Silently ignore errors when cleaning cache - } - // No caching, just transform the object directly - await transformObjectWithOptions(obj, transformer, { - jsonPath, - targetPath, - throttleDelay, - concurrentTasks, - errorCallback, - filterCallback, - maxRetries: mappingRetries || maxRetries, - retryDelay: mappingRetryDelay || retryDelay - }); - } + await transformObjectWithOptions(obj, transformer, { + jsonPath, + targetPath, + throttleDelay, + concurrentTasks, + errorCallback, + filterCallback, + maxRetries: mappingRetries || maxRetries, + retryDelay: mappingRetryDelay || retryDelay + }); } } }; } -// Extract transformed data based on the jsonPath and targetPath -function extractTransformedData(obj, jsonPath, targetPath) { - const paths = JSONPath({ path: jsonPath, json: obj, resultType: 'pointer' }); - const result = {}; - for (const p of paths) { - const keys = p.slice(1).split('/'); - let current = obj; - // Navigate to the value - for (const key of keys) { - if (key === '') - continue; - if (current === undefined || current === null) - break; - current = current[key]; - } - // Store the value in the result - if (current !== undefined) { - if (targetPath) { - // For target path transformations (like marketingName), - // store the actual transformed value instead of the original value - if (typeof current === 'object' && current !== null && targetPath in current) { - result[p] = { [targetPath]: current[targetPath] }; - } - else { - // This is the raw value from the LLM - use this as is - result[p] = { [targetPath]: current }; - } - } - else { - result[p] = current; - } - } - } - return result; -} -// Apply transformed data to the original object -function applyTransformResult(obj, jsonPath, targetPath, transformedData) { - for (const [path, value] of Object.entries(transformedData)) { - const keys = path.slice(1).split('/'); - let current = obj; - // Navigate to the parent object - for (let i = 0; i < keys.length - 1; i++) { - const key = keys[i]; - if (key === '') - continue; - if (current[key] === undefined) { - current[key] = {}; - } - current = current[key]; - } - // Apply the value - const lastKey = keys[keys.length - 1]; - if (lastKey !== '') { - if (targetPath) { - // Check if current[lastKey] is an object, if not convert it to an object - if (typeof current[lastKey] !== 'object' || current[lastKey] === null) { - // Save the original value - const originalValue = current[lastKey]; - // Convert to object - current[lastKey] = { value: originalValue }; - } - // Update the targetPath property with the value from the transformer, not the original value - if (typeof value === 'object' && value !== null && value[targetPath] !== undefined) { - current[lastKey][targetPath] = value[targetPath]; - } - } - else { - current[lastKey] = value; - } - } - } -} export async function transformWithMappings(obj, createTransformer, mappings, globalOptions = {}) { - const { throttleDelay = 1000, concurrentTasks = 1, errorCallback = defaultError, filterCallback = testFilters(defaultFilters()), maxRetries = 3, retryDelay = 2000, cache, logger } = globalOptions; + const { throttleDelay = 1000, concurrentTasks = 1, errorCallback = defaultError, filterCallback = testFilters(defaultFilters()), maxRetries = 3, retryDelay = 2000, logger } = globalOptions; const iterator = createIterator(obj, {}, { throttleDelay, concurrentTasks, @@ -338,9 +109,8 @@ export async function transformWithMappings(obj, createTransformer, mappings, gl transformerFactory: createTransformer, maxRetries, retryDelay, - cache, logger }); await iterator.transform(mappings); } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXRlcmF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaXRlcmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFtRCxZQUFZLEVBQUUsY0FBYyxFQUFFLFdBQVcsRUFBRSwwQkFBMEIsRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQzVKLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFFeEMsMERBQTBEO0FBQzFELElBQUksV0FBVyxHQUlKLElBQUksQ0FBQztBQUVoQix3Q0FBd0M7QUFDeEMsTUFBTSxVQUFVLG1CQUFtQixDQUFDLE1BQTBCO0lBQzFELFdBQVcsR0FBRyxNQUFNLENBQUM7QUFDekIsQ0FBQztBQVNELHFDQUFxQztBQUNyQyxNQUFNLE9BQU8sU0FBUztJQUNsQixLQUFLLENBQUMsR0FBRyxDQUFDLElBQVMsSUFBSSxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDckMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFTLEVBQUUsTUFBVyxJQUFJLE9BQU8sQ0FBQyxDQUFDO0lBQzdDLEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBUyxJQUFJLE9BQU8sQ0FBQyxDQUFDO0NBQ3RDO0FBRUQsd0RBQXdEO0FBQ3hELE1BQU0sT0FBTyxZQUFZO0lBQ1E7SUFBN0IsWUFBNkIsTUFBMEQ7UUFBMUQsV0FBTSxHQUFOLE1BQU0sQ0FBb0Q7SUFBRyxDQUFDO0lBRTNGLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBUTtRQUNkLElBQUksQ0FBQyxXQUFXO1lBQUUsT0FBTyxJQUFJLENBQUM7UUFFOUIsSUFBSSxDQUFDO1lBQ0QsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDLElBQUksSUFBSSxVQUFVLENBQUM7WUFDekMsTUFBTSxNQUFNLEdBQUcsTUFBTSxXQUFXLENBQUMsaUJBQWlCLENBQUMsR0FBRyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1lBQ25FLE9BQU8sTUFBTSxDQUFDO1FBQ2xCLENBQUM7UUFB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 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXRlcmF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaXRlcmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFtRCxZQUFZLEVBQUUsY0FBYyxFQUFFLFdBQVcsRUFBRSwwQkFBMEIsRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQzVKLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUN2QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsaUJBQWlCLEVBQW9CLE1BQU0saUJBQWlCLENBQUE7QUFFeEYsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxHQUFRLEVBQU8sRUFBRTtJQUNoRCxJQUFJLEdBQUcsS0FBSyxJQUFJLElBQUksR0FBRyxLQUFLLFNBQVM7UUFBRSxPQUFPLEdBQUcsQ0FBQztJQUNsRCxLQUFLLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ3BCLE1BQU0sR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUNwQixJQUFJLEdBQUcsS0FBSyxJQUFJLElBQUksR0FBRyxLQUFLLFNBQVM7WUFBRSxTQUFTO1FBQ2hELElBQUksT0FBTyxHQUFHLEtBQUssUUFBUTtZQUN2QixDQUFDLEdBQUcsSUFBSSxPQUFPLElBQUksT0FBTyxHQUFHLEtBQUssUUFBUSxJQUFJLEdBQUcsS0FBSyxDQUFDLElBQUksR0FBRyxJQUFJLFFBQVEsQ0FBQyxFQUM3RSxDQUFDO1lBQ0MsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ3hDLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQ3JDLE9BQU8sR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ3BCLENBQUM7UUFDTCxDQUFDO0lBQ0wsQ0FBQztJQUNELE9BQU8sR0FBRyxDQUFBO0FBQ2QsQ0FBQyxDQUFBO0FBZUQsTUFBTSxVQUFVLG9CQUFvQixDQUNoQyxPQUFrQixFQUNsQixNQUlDO0lBRUQsT0FBTyxLQUFLLEVBQUUsS0FBYSxFQUFFLFFBQWdCLEVBQW1CLEVBQUU7UUFDOUQsSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUNULE1BQU0sQ0FBQyxJQUFJLENBQUMsK0JBQStCLFFBQVEsRUFBRSxDQUFDLENBQUM7WUFDdkQsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDL0IsTUFBTSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDbkQsQ0FBQztRQUVELE1BQU0sUUFBUSxHQUFjO1lBQ3hCLEdBQUcsT0FBTztZQUNWLE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyxNQUFNLDJCQUEyQixLQUFLLEdBQUc7U0FDL0QsQ0FBQztRQUVGLG9DQUFvQztRQUNwQyxNQUFNLFdBQVcsR0FBRyxrQkFBa0IsQ0FBQztZQUNuQyxNQUFNLEVBQUUsUUFBUSxDQUFDLE1BQU07WUFDdkIsS0FBSyxFQUFFLFFBQVEsQ0FBQyxLQUFLO1lBQ3JCLE1BQU0sRUFBRSxRQUFRLENBQUMsTUFBTTtZQUN2QixJQUFJLEVBQUUsUUFBUSxDQUFDLElBQUk7WUFDbkIsT0FBTyxFQUFFLEVBQUU7WUFDWCxLQUFLLEVBQUUsRUFBRTtTQUNaLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQztZQUVELE1BQU0sY0FBYyxHQUFHLE1BQU0saUJBQWlCLENBQUMsRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLEVBQUUsZUFBZSxDQUF3QixDQUFDO1lBQ3BILElBQUksY0FBYyxFQUFFLE9BQU8sRUFBRSxDQUFDO2dCQUMxQixJQUFJLE1BQU07b0JBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyx5Q0FBeUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDekcsT0FBTyxjQUFjLENBQUMsT0FBTyxDQUFDO1lBQ2xDLENBQUM7WUFDRCxNQUFNLE9BQU8sR0FBRyxNQUFNLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQTtZQUNuQyxJQUFJLE9BQU8sSUFBSSxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxPQUFPLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDbEUsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO2dCQUNqQyxNQUFNLGlCQUFpQixDQUFDLEVBQUUsVUFBVSxFQUFFLFdBQVcsRUFBRSxFQUFFLGVBQWUsRUFBRSxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFDL0YsSUFBSSxNQUFNO29CQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsbUNBQW1DLFFBQVEsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBRW5HLElBQUksTUFBTTtvQkFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFdBQVcsTUFBTSxFQUFFLENBQUMsQ0FBQztnQkFDN0MsT0FBTyxNQUFNLENBQUM7WUFDbEIsQ0FBQztZQUVELElBQUksTUFBTTtnQkFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLGdDQUFnQyxRQUFRLHNCQUFzQixDQUFDLENBQUM7WUFDeEYsT0FBTyxLQUFLLENBQUM7UUFDakIsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDYixJQUFJLE1BQU0sRUFBRSxDQUFDO2dCQUNULE1BQU0sQ0FBQyxLQUFLLENBQUMsMEJBQTBCLEtBQUssQ0FBQyxPQUFPLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNuRSxDQUFDO2lCQUFNLENBQUM7Z0JBQ0osT0FBTyxDQUFDLEtBQUssQ0FBQywwQkFBMEIsS0FBSyxDQUFDLE9BQU8sRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3BFLENBQUM7WUFDRCxPQUFPLEtBQUssQ0FBQztRQUNqQixDQUFDO0lBQ0wsQ0FBQyxDQUFDO0FBQ04sQ0FBQztBQUVELE1BQU0sVUFBVSxjQUFjLENBQzFCLEdBQXdCLEVBQ3hCLFlBQWdDLEVBQ2hDLGdCQVNJLEVBQUU7SUFFTixNQUFNLEVBQ0YsYUFBYSxHQUFHLElBQUksRUFDcEIsZUFBZSxHQUFHLENBQUMsRUFDbkIsYUFBYSxHQUFHLFlBQVksRUFDNUIsY0FBYyxHQUFHLFdBQVcsQ0FBQyxjQUFjLEVBQUUsQ0FBQyxFQUM5QyxrQkFBa0IsRUFDbEIsVUFBVSxHQUFHLENBQUMsRUFDZCxVQUFVLEdBQUcsSUFBSSxFQUNqQixNQUFNLEVBQ1QsR0FBRyxhQUFhLENBQUM7SUFFbEIsTUFBTSx5QkFBeUIsR0FBRyxDQUFDLE9BQWtCLEVBQW9CLEVBQUU7UUFDdkUsZ0VBQWdFO1FBQ2hFLDJFQUEyRTtRQUMzRSxPQUFPLEtBQUssRUFBRSxLQUFhLEVBQW1CLEVBQUUsQ0FBQyxLQUFLLENBQUM7SUFDM0QsQ0FBQyxDQUFDO0lBRUYsTUFBTSxpQkFBaUIsR0FBRyxrQkFBa0IsSUFBSSx5QkFBeUIsQ0FBQztJQUUxRSxPQUFPO1FBQ0gsaUJBQWlCO1FBQ2pCLFNBQVMsRUFBRSxLQUFLLEVBQUUsUUFBd0IsRUFBaUIsRUFBRTtZQUN6RCxLQUFLLE1BQU0sT0FBTyxJQUFJLFFBQVEsRUFBRSxDQUFDO2dCQUM3QixNQUFNLGFBQWEsR0FBRyxFQUFFLEdBQUcsWUFBWSxFQUFFLEdBQUcsT0FBTyxDQUFDLE9BQU8sRUFBZSxDQUFDO2dCQUMzRSxNQUFNLEVBQUUsUUFBUSxFQUFFLFVBQVUsR0FBRyxJQUFJLEVBQUUsVUFBVSxFQUFFLGNBQWMsRUFBRSxVQUFVLEVBQUUsaUJBQWlCLEVBQUUsR0FBRyxPQUFPLENBQUM7Z0JBQzNHLE1BQU0sV0FBVyxHQUFHLGlCQUFpQixDQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUNyRCxNQUFNLDBCQUEwQixDQUM1QixHQUFHLEVBQ0gsV0FBVyxFQUNYO29CQUNJLFFBQVE7b0JBQ1IsVUFBVTtvQkFDVixhQUFhO29CQUNiLGVBQWU7b0JBQ2YsYUFBYTtvQkFDYixjQUFjO29CQUNkLFVBQVUsRUFBRSxjQUFjLElBQUksVUFBVTtvQkFDeEMsVUFBVSxFQUFFLGlCQUFpQixJQUFJLFVBQVU7aUJBQzlDLENBQ0osQ0FBQztZQUNOLENBQUM7UUFDTCxDQUFDO0tBQ0osQ0FBQztBQUNOLENBQUM7QUFFRCxNQUFNLENBQUMsS0FBSyxVQUFVLHFCQUFxQixDQUN2QyxHQUF3QixFQUN4QixpQkFBMkQsRUFDM0QsUUFBd0IsRUFDeEIsZ0JBUUksRUFBRTtJQUVOLE1BQU0sRUFDRixhQUFhLEdBQUcsSUFBSSxFQUNwQixlQUFlLEdBQUcsQ0FBQyxFQUNuQixhQUFhLEdBQUcsWUFBWSxFQUM1QixjQUFjLEdBQUcsV0FBVyxDQUFDLGNBQWMsRUFBRSxDQUFDLEVBQzlDLFVBQVUsR0FBRyxDQUFDLEVBQ2QsVUFBVSxHQUFHLElBQUksRUFDakIsTUFBTSxFQUNULEdBQUcsYUFBYSxDQUFDO0lBRWxCLE1BQU0sUUFBUSxHQUFHLGNBQWMsQ0FDM0IsR0FBRyxFQUNILEVBQUUsRUFDRjtRQUNJLGFBQWE7UUFDYixlQUFlO1FBQ2YsYUFBYTtRQUNiLGNBQWM7UUFDZCxrQkFBa0IsRUFBRSxpQkFBaUI7UUFDckMsVUFBVTtRQUNWLFVBQVU7UUFDVixNQUFNO0tBQ1QsQ0FDSixDQUFDO0lBRUYsTUFBTSxRQUFRLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBQ3ZDLENBQUMifQ== \ No newline at end of file diff --git a/packages/kbot/package-lock.json b/packages/kbot/package-lock.json index 35433d58..ed8893ff 100644 --- a/packages/kbot/package-lock.json +++ b/packages/kbot/package-lock.json @@ -9,6 +9,7 @@ "version": "0.3.5", "dependencies": { "@polymech/ai-tools": "file:../ai-tools", + "@polymech/cache": "file:../cache", "@polymech/commons": "file:../commons", "@polymech/core": "file:../core", "@polymech/fs": "file:../fs", @@ -109,6 +110,26 @@ "puppeteer": "^24.2.1" } }, + "../cache": { + "name": "@polymech/cache", + "version": "0.4.8", + "license": "BSD-3-Clause", + "dependencies": { + "@polymech/commons": "file:../commons", + "@polymech/core": "file:../core", + "@polymech/fs": "file:../fs", + "@polymech/log": "file:../log", + "@types/node": "^22.10.2", + "cacache": "^19.0.1", + "md5": "^2.3.0", + "p-map": "^7.0.3", + "ssri": "^10.0.1", + "yargs": "^17.7.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, "../commons": { "name": "@polymech/commons", "version": "0.2.6", @@ -1359,6 +1380,10 @@ "resolved": "../ai-tools", "link": true }, + "node_modules/@polymech/cache": { + "resolved": "../cache", + "link": true + }, "node_modules/@polymech/commons": { "resolved": "../commons", "link": true diff --git a/packages/kbot/package.json b/packages/kbot/package.json index 04a1c8cc..cb34e117 100644 --- a/packages/kbot/package.json +++ b/packages/kbot/package.json @@ -41,6 +41,7 @@ }, "dependencies": { "@polymech/ai-tools": "file:../ai-tools", + "@polymech/cache": "file:../cache", "@polymech/commons": "file:../commons", "@polymech/core": "file:../core", "@polymech/fs": "file:../fs", diff --git a/packages/kbot/src/commands/run.ts b/packages/kbot/src/commands/run.ts index f8e934fc..8f029451 100644 --- a/packages/kbot/src/commands/run.ts +++ b/packages/kbot/src/commands/run.ts @@ -144,7 +144,7 @@ export const execute_request = async ( params: ChatCompletionToolRunnerParams ): Promise => { let ret: any = null - + try { switch (options.mode) { case E_Mode.COMPLETION: diff --git a/packages/kbot/src/examples/core/iterator-factory-example.ts b/packages/kbot/src/examples/core/iterator-factory-example.ts index a9c7706e..e80c619d 100644 --- a/packages/kbot/src/examples/core/iterator-factory-example.ts +++ b/packages/kbot/src/examples/core/iterator-factory-example.ts @@ -4,40 +4,8 @@ import * as fs from 'fs'; import type { IKBotTask } from '@polymech/ai-tools'; import { E_OPENROUTER_MODEL } from '../../models/cache/openrouter-models.js'; import { E_Mode } from '../../zod_schema.js'; -import { AsyncTransformer } from '../../async-iterator.js'; -import { FieldMapping, createIterator, DefaultCache, registerCacheModule } from '../../iterator.js'; -import { run } from '../../commands/run.js'; -// Clear the mock cache for fresh testing -const mockCacheModule = { - _cache: new Map(), - get_cached_object: async (key: any, namespace: string) => { - const cacheKey = JSON.stringify({ key, namespace }); - console.log(`Cache: Looking up ${cacheKey}`); - return mockCacheModule._cache.get(cacheKey) || null; - }, - set_cached_object: async (key: any, namespace: string, value: any) => { - const cacheKey = JSON.stringify({ key, namespace }); - console.log(`Cache: Storing in ${cacheKey}`); - mockCacheModule._cache.set(cacheKey, value); - // Show what's being stored for debugging - console.log(`Cache value stored: ${JSON.stringify(value, null, 2).substring(0, 100)}...`); - }, - rm_cached_object: async (key: any, namespace: string) => { - const cacheKey = JSON.stringify({ key, namespace }); - console.log(`Cache: REMOVING ${cacheKey}`); - - // Check if it existed before removal - const existed = mockCacheModule._cache.has(cacheKey); - mockCacheModule._cache.delete(cacheKey); - - // Show removal status - console.log(`Cache removal: ${existed ? 'REMOVED EXISTING CACHE VALUE' : 'NO CACHE VALUE FOUND'}`); - } -}; - -// Register our mock cache module -registerCacheModule(mockCacheModule); +import { FieldMapping, createIterator, createLLMTransformer } from '../../iterator.js'; const MODEL = E_OPENROUTER_MODEL.MODEL_OPENROUTER_QUASAR_ALPHA; const ROUTER = 'openrouter'; @@ -104,36 +72,6 @@ const fieldMappings: FieldMapping[] = [ } ]; -// Create LLM transformer factory -const createLLMTransformer = (options: IKBotTask): AsyncTransformer => { - return async (input: string, jsonPath: string): Promise => { - logger.info(`Transforming field at path: ${jsonPath}`); - logger.info(`Input: ${input}`); - logger.info(`Using prompt: ${options.prompt}`); - - const kbotTask: IKBotTask = { - ...options, - prompt: `${options.prompt}\n\nText to transform: "${input}"`, - }; - - try { - const results = await run(kbotTask); - - if (results && results.length > 0 && typeof results[0] === 'string') { - const result = results[0].trim(); - logger.info(`Result: ${result}`); - return result; - } - - logger.warn(`No valid result received for ${jsonPath}, returning original`); - return input; - } catch (error) { - console.error(`Error calling LLM API: ${error.message}`, error); - return input; - } - }; -}; - // Error handler const errorCallback = (path: string, value: string, error: any) => { logger.error(`Error transforming ${path}: ${error.message}`); @@ -175,7 +113,7 @@ export async function factoryExample() { concurrentTasks: 1, errorCallback, filterCallback: async () => true, - transformerFactory: createLLMTransformer, + transformerFactory: (options) => createLLMTransformer(options, logger), logger: logger, cache: { enabled: true, @@ -210,7 +148,7 @@ export async function factoryExample() { concurrentTasks: 1, errorCallback, filterCallback: async () => true, - transformerFactory: createLLMTransformer, + transformerFactory: (options) => createLLMTransformer(options, logger), logger: logger, cache: { enabled: true, @@ -222,58 +160,6 @@ export async function factoryExample() { // Should use cached values await iterator2.transform(fieldMappings); - // Manually set the marketingName for demonstration purposes - data2.products.fruits[0].name = { - value: "apple", - marketingName: "Crimson Orchard Delight" - }; - data2.products.fruits[1].name = { - value: "banana", - marketingName: "Golden Delight Banana" - }; - - // Now create a third instance with caching disabled to demonstrate cache cleanup - console.log("\n\n========================================"); - console.log("Third run - with caching disabled (should clean up cache):"); - console.log("========================================"); - - /* - const data3 = JSON.parse(JSON.stringify(exampleData)); - - const iterator3 = createIterator( - data3, - globalOptionsMixin, - { - throttleDelay: 1000, - concurrentTasks: 1, - errorCallback, - filterCallback: async () => true, - transformerFactory: createLLMTransformer, - logger: logger, - cache: { - enabled: false, // Caching disabled - namespace: 'product-transformations' - } - } - ); - - // Should transform again and remove the cache - await iterator3.transform(fieldMappings); - - // Verify cache was removed by checking if it still exists - console.log("\nVerifying cache removal:"); - const cacheKey = { - key: JSON.stringify({ - jsonPath: '$..name', - targetPath: 'marketingName', - options: { ...globalOptionsMixin, prompt: 'Generate a more appealing marketing name for this product' } - }), - name: 'product-transformations' - }; - const cachedValue = await mockCacheModule.get_cached_object(cacheKey, 'product-transformations'); - console.log(`Cache still exists? ${cachedValue !== null ? 'Yes' : 'No'}`); - */ - console.log("\nBefore/After Comparison Example:"); console.log(`Original description: ${exampleData.products.fruits[0].description}`); console.log(`Transformed description: ${data.products.fruits[0].description}`); @@ -291,21 +177,13 @@ export async function factoryExample() { } } -console.log("Module loading, checking if this is direct execution"); -console.log("process.argv[1]:", process.argv[1]); -console.log("import.meta.url:", import.meta.url); - -const isDirectExecution = process.argv[1] && process.argv[1].includes('iterator-factory-example'); -console.log("Is direct execution:", isDirectExecution); - -if (isDirectExecution) { +if (process.argv[1] && process.argv[1].includes('iterator-factory-example')) { const isDebug = process.argv.includes('--debug'); console.log('Starting iterator factory example...'); console.log(`Command arguments: ${process.argv.slice(2).join(', ')}`); console.log(`Debug mode: ${isDebug ? 'enabled' : 'disabled'}`); if (isDebug) { - // Set up debug logging console.log("Running in debug mode with verbose output"); } diff --git a/packages/kbot/src/iterator.ts b/packages/kbot/src/iterator.ts index f9e3baa6..56b700a9 100644 --- a/packages/kbot/src/iterator.ts +++ b/packages/kbot/src/iterator.ts @@ -1,89 +1,23 @@ import { IKBotTask } from '@polymech/ai-tools' import { AsyncTransformer, ErrorCallback, FilterCallback, defaultError, defaultFilters, testFilters, transformObjectWithOptions } from './async-iterator.js' -import { JSONPath } from 'jsonpath-plus' -import { deepClone } from '@polymech/core/objects' -// Add an optional import that can be provided by the user -let cacheModule: { - get_cached_object: (key: any, namespace: string) => Promise; - set_cached_object: (key: any, namespace: string, value: any, options?: any) => Promise; - rm_cached_object: (key: any, namespace: string) => Promise; -} | null = null; +import { run } from './commands/run.js' +import { get_cached_object, set_cached_object, rm_cached_object } from "@polymech/cache" -// Function to register the cache module -export function registerCacheModule(module: typeof cacheModule) { - cacheModule = module; -} - -// Cache interface - users can implement to connect different cache systems -export interface CacheInterface { - get: (key: any) => Promise; - set: (key: any, value: any) => Promise; - delete?: (key: any) => Promise; -} - -// Default no-op cache implementation -export class NoopCache implements CacheInterface { - async get(_key: any) { return null; } - async set(_key: any, _value: any) { return; } - async delete(_key: any) { return; } -} - -// Default cache implementation based on kbot.ts pattern -export class DefaultCache implements CacheInterface { - constructor(private readonly logger?: { error: (message: string, error?: any) => void }) {} - - async get(key: any): Promise { - if (!cacheModule) return null; - - try { - const namespace = key.name || 'iterator'; - const cached = await cacheModule.get_cached_object(key, namespace); - return cached; - } catch (e) { - if (this.logger) { - this.logger.error(`Failed to get cached object for key: ${JSON.stringify(key).substring(0, 50)}`, e); - } else { - console.error(`Cache get error:`, e); - } - return null; - } - } - - async set(key: any, value: any): Promise { - if (!cacheModule) return; - - try { - const namespace = key.name || 'iterator'; - await cacheModule.set_cached_object(key, namespace, value, {}); - } catch (e) { - if (this.logger) { - this.logger.error(`Failed to cache object for key: ${JSON.stringify(key).substring(0, 50)}`, e); - } else { - console.error(`Cache set error:`, e); +export const removeEmptyObjects = (obj: any): any => { + if (obj === null || obj === undefined) return obj; + for (const key in obj) { + const val = obj[key] + if (val === null || val === undefined) continue; + if (typeof val === 'object' || + (key == 'value' && typeof val === 'number' && val === 0 || key == 'base64') + ) { + obj[key] = removeEmptyObjects(obj[key]); + if (Object.keys(obj[key]).length === 0) { + delete obj[key]; } } } - - async delete(key: any): Promise { - if (!cacheModule) return; - - try { - const namespace = key.name || 'iterator'; - await cacheModule.rm_cached_object(key, namespace); - } catch (e) { - if (this.logger) { - this.logger.error(`Failed to delete cached object for key: ${JSON.stringify(key).substring(0, 50)}`, e); - } else { - console.error(`Cache delete error:`, e); - } - } - } -} - -export interface CacheOptions { - enabled: boolean; - implementation?: CacheInterface; - namespace?: string; + return obj } export interface FieldMapping { @@ -99,45 +33,64 @@ export interface IteratorFactory { createTransformer: (options: IKBotTask) => AsyncTransformer } -// Utility function to create a cache key from an object -export function createCacheKey(obj: any): string { - try { - const cleanObj = JSON.parse(JSON.stringify(removeEmptyValues(obj))); - return JSON.stringify(cleanObj); - } catch (e) { - console.error("Error creating cache key:", e); - // Fallback to simpler stringification if error occurs - return JSON.stringify({ hash: String(Date.now()) }); +export function createLLMTransformer( + options: IKBotTask, + logger?: { + info: (message: string) => void; + warn: (message: string) => void; + error: (message: string, error?: any) => void; } -} - -// Utility to remove null, undefined, and empty objects from an object for cache key generation -export function removeEmptyValues(obj: any): any { - if (obj === null || obj === undefined) { - return undefined; - } - - if (typeof obj !== 'object') { - return obj; - } - - if (Array.isArray(obj)) { - const filtered = obj.map(removeEmptyValues).filter(v => v !== undefined); - return filtered.length ? filtered : undefined; - } - - const result: Record = {}; - let hasValues = false; - - for (const [key, value] of Object.entries(obj)) { - const cleaned = removeEmptyValues(value); - if (cleaned !== undefined) { - result[key] = cleaned; - hasValues = true; +): AsyncTransformer { + 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}`); } - } - - return hasValues ? result : undefined; + + const kbotTask: IKBotTask = { + ...options, + prompt: `${options.prompt}\n\nText to transform: "${input}"`, + }; + + // Create cache key for the LLM call + const cacheKeyObj = removeEmptyObjects({ + prompt: kbotTask.prompt, + model: kbotTask.model, + router: kbotTask.router, + mode: kbotTask.mode, + filters: [], + tools: [] + }); + + try { + + const cachedResponse = await get_cached_object({ ca_options: cacheKeyObj }, 'llm-responses') as { content: string }; + if (cachedResponse?.content) { + if (logger) logger.info(`Using cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`); + return cachedResponse.content; + } + const results = await run(kbotTask) + if (results && results.length > 0 && typeof results[0] === 'string') { + const result = results[0].trim(); + await set_cached_object({ ca_options: cacheKeyObj }, 'llm-responses', { content: result }, {}); + if (logger) logger.info(`Cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`); + + if (logger) logger.info(`Result: ${result}`); + return result; + } + + if (logger) 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); + } + return input; + } + }; } export function createIterator( @@ -151,7 +104,6 @@ export function createIterator( transformerFactory?: (options: IKBotTask) => AsyncTransformer maxRetries?: number retryDelay?: number - cache?: CacheOptions logger?: { error: (message: string, error?: any) => void } } = {} ): IteratorFactory { @@ -163,7 +115,6 @@ export function createIterator( transformerFactory, maxRetries = 3, retryDelay = 2000, - cache, logger } = globalOptions; @@ -172,244 +123,35 @@ export function createIterator( // In real usage, this would be replaced by the provided transformerFactory return async (input: string): Promise => input; }; - - const createTransformer = transformerFactory || defaultTransformerFactory; - // Default cache settings - const defaultImplementation = logger ? new DefaultCache(logger) : new DefaultCache(); - const cacheImpl = cache?.implementation || defaultImplementation; - const cacheEnabled = cache?.enabled || false; - const cacheNamespace = cache?.namespace || 'iterator'; + const createTransformer = transformerFactory || defaultTransformerFactory; return { createTransformer, transform: async (mappings: FieldMapping[]): Promise => { for (const mapping of mappings) { - // Merge the mapping options with the global mixin const mergedOptions = { ...optionsMixin, ...mapping.options } as IKBotTask; const { jsonPath, targetPath = null, maxRetries: mappingRetries, retryDelay: mappingRetryDelay } = mapping; const transformer = createTransformer(mergedOptions); - - // Generate cache key for this transformation - if (cacheEnabled) { - const cacheKeyObj = { + await transformObjectWithOptions( + obj, + transformer, + { jsonPath, targetPath, - options: mergedOptions, + throttleDelay, + concurrentTasks, + errorCallback, + filterCallback, maxRetries: mappingRetries || maxRetries, retryDelay: mappingRetryDelay || retryDelay - }; - - const cacheKey = { key: createCacheKey(cacheKeyObj), name: cacheNamespace }; - - // Check if we have a cached result - try { - const cachedResult = await cacheImpl.get(cacheKey); - if (cachedResult) { - // Apply cached result directly - applyTransformResult(obj, jsonPath, targetPath, cachedResult); - continue; // Skip to next mapping - } - } catch (e) { - errorCallback('cache', 'get', e); } - - // For paths with targetPath, we need special handling for the LLM results - if (targetPath) { - // Get all the values that need transformation - const paths = JSONPath({ path: jsonPath, json: obj, resultType: 'pointer' }); - const transformedData: Record = {}; - - for (const path of paths) { - // Extract the value to transform - const keys = path.slice(1).split('/'); - let current = obj; - - for (const key of keys) { - if (key === '') continue; - if (current === undefined || current === null) break; - current = current[key]; - } - - // Transform the value if it exists - if (current !== undefined) { - try { - // Perform the transformation using the LLM - const rawValue = typeof current === 'object' && current !== null && 'value' in current - ? current.value - : current; - - const result = await transformer(String(rawValue), path); - - // Store the result with the target path - transformedData[path] = { [targetPath]: result }; - } catch (e) { - errorCallback(path, String(current), e); - } - } - } - - // Store the result in the cache - if (Object.keys(transformedData).length > 0) { - try { - await cacheImpl.set(cacheKey, transformedData); - } catch (e) { - errorCallback('cache', 'set', e); - } - - // Apply the transformations - applyTransformResult(obj, jsonPath, targetPath, transformedData); - } - } else { - // Regular case without targetPath - use normal approach - // Create a deep clone to transform - const objCopy = JSON.parse(JSON.stringify(obj)); - - // Perform the transformation - await transformObjectWithOptions( - objCopy, - transformer, - { - jsonPath, - targetPath, - throttleDelay, - concurrentTasks, - errorCallback, - filterCallback, - maxRetries: mappingRetries || maxRetries, - retryDelay: mappingRetryDelay || retryDelay - } - ); - - // Store the result in the cache - try { - // Extract the transformed parts to store in cache - const transformedData = extractTransformedData(objCopy, jsonPath, targetPath); - await cacheImpl.set(cacheKey, transformedData); - } catch (e) { - errorCallback('cache', 'set', e); - } - - // Apply the transformation to the original object - applyTransformResult(obj, jsonPath, targetPath, extractTransformedData(objCopy, jsonPath, targetPath)); - } - } else { - // Caching is disabled, but check if there are old cached values that should be removed - try { - // Create the same cacheKeyObj as used when caching is enabled - const keyObj = { - jsonPath, - targetPath, - options: mergedOptions, - maxRetries: mappingRetries || maxRetries, - retryDelay: mappingRetryDelay || retryDelay - }; - const cacheKey = { key: createCacheKey(keyObj), name: cacheNamespace }; - const cachedResult = await cacheImpl.get(cacheKey); - if (cachedResult && cacheImpl.delete) { - // If item exists in cache but caching is disabled, remove it - await cacheImpl.delete(cacheKey); - } - } catch (e) { - // Silently ignore errors when cleaning cache - } - - // No caching, just transform the object directly - await transformObjectWithOptions( - obj, - transformer, - { - jsonPath, - targetPath, - throttleDelay, - concurrentTasks, - errorCallback, - filterCallback, - maxRetries: mappingRetries || maxRetries, - retryDelay: mappingRetryDelay || retryDelay - } - ); - } + ); } } }; } -// Extract transformed data based on the jsonPath and targetPath -function extractTransformedData(obj: Record, jsonPath: string, targetPath: string | null): any { - const paths = JSONPath({ path: jsonPath, json: obj, resultType: 'pointer' }); - const result: Record = {}; - - for (const p of paths) { - const keys = p.slice(1).split('/'); - let current = obj; - - // Navigate to the value - for (const key of keys) { - if (key === '') continue; - if (current === undefined || current === null) break; - current = current[key]; - } - - // Store the value in the result - if (current !== undefined) { - if (targetPath) { - // For target path transformations (like marketingName), - // store the actual transformed value instead of the original value - if (typeof current === 'object' && current !== null && targetPath in current) { - result[p] = { [targetPath]: current[targetPath] }; - } else { - // This is the raw value from the LLM - use this as is - result[p] = { [targetPath]: current }; - } - } else { - result[p] = current; - } - } - } - - return result; -} - -// Apply transformed data to the original object -function applyTransformResult(obj: Record, jsonPath: string, targetPath: string | null, transformedData: Record): void { - for (const [path, value] of Object.entries(transformedData)) { - const keys = path.slice(1).split('/'); - let current = obj; - - // Navigate to the parent object - for (let i = 0; i < keys.length - 1; i++) { - const key = keys[i]; - if (key === '') continue; - if (current[key] === undefined) { - current[key] = {}; - } - current = current[key]; - } - - // Apply the value - const lastKey = keys[keys.length - 1]; - if (lastKey !== '') { - if (targetPath) { - // Check if current[lastKey] is an object, if not convert it to an object - if (typeof current[lastKey] !== 'object' || current[lastKey] === null) { - // Save the original value - const originalValue = current[lastKey]; - // Convert to object - current[lastKey] = { value: originalValue }; - } - - // Update the targetPath property with the value from the transformer, not the original value - if (typeof value === 'object' && value !== null && value[targetPath] !== undefined) { - current[lastKey][targetPath] = value[targetPath]; - } - } else { - current[lastKey] = value; - } - } - } -} - export async function transformWithMappings( obj: Record, createTransformer: (options: IKBotTask) => AsyncTransformer, @@ -421,7 +163,6 @@ export async function transformWithMappings( filterCallback?: FilterCallback maxRetries?: number retryDelay?: number - cache?: CacheOptions logger?: { error: (message: string, error?: any) => void } } = {} ): Promise { @@ -432,13 +173,12 @@ export async function transformWithMappings( filterCallback = testFilters(defaultFilters()), maxRetries = 3, retryDelay = 2000, - cache, logger } = globalOptions; const iterator = createIterator( - obj, - {}, + obj, + {}, { throttleDelay, concurrentTasks, @@ -447,10 +187,9 @@ export async function transformWithMappings( transformerFactory: createTransformer, maxRetries, retryDelay, - cache, logger } ); - + await iterator.transform(mappings); } \ No newline at end of file diff --git a/packages/kbot/tests/test-data/core/iterator-factory-data.json b/packages/kbot/tests/test-data/core/iterator-factory-data.json index 20224f1d..7a1f9f61 100644 --- a/packages/kbot/tests/test-data/core/iterator-factory-data.json +++ b/packages/kbot/tests/test-data/core/iterator-factory-data.json @@ -3,29 +3,25 @@ "fruits": [ { "id": "f1", - "name": { - "value": "apple", - "marketingName": "Crimson Orchard Delight" - }, - "description": "A deliciously sweet, juicy fruit with a satisfying crunch, bursting with refreshing flavor that delights your senses and offers a perfect balance of crisp texture and natural sweetness.", + "name": "apple", + "description": "A deliciously juicy fruit bursting with natural sweetness, offering a satisfying crunch with every bite—a perfect refreshing snack packed with vitamins and vibrant flavor.", "details": { "color": "red", "origin": "Worldwide", - "nutrition": "Rich in fiber and vitamin C, which supports digestive health, promotes healthy gut bacteria, and boosts immune function. Vitamin C also aids collagen production for skin health and enhances iron absorption." - } + "nutrition": "Rich in fiber and vitamin C, which supports a healthy digestive system, aids in maintaining stable blood sugar levels, strengthens the immune system, and promotes collagen production for healthier skin and faster wound healing." + }, + "marketingName": "Crimson Orchard Essence" }, { "id": "f2", - "name": { - "value": "banana", - "marketingName": "Golden Tropic Delight" - }, - "description": "A vibrant, sun-kissed yellow tropical fruit with a sweet, juicy flesh and an enticing aroma, bursting with refreshing flavor reminiscent of sunshine and warm island breezes.", + "name": "banana", + "description": "A vibrant, sun-kissed tropical fruit with a bright yellow hue, boasting a sweet, juicy flavor that bursts with refreshing tropical essence in every delicious bite.", "details": { "color": "yellow", "origin": "Southeast Asia", - "nutrition": "High in potassium, which helps maintain healthy blood pressure levels, supports proper muscle function, and promotes optimal nerve signaling, contributing to overall cardiovascular health and helping reduce the risk of stroke." - } + "nutrition": "High in potassium, which supports healthy nerve and muscle function, helps maintain normal blood pressure, and reduces the risk of stroke by balancing sodium levels in the body for overall cardiovascular health." + }, + "marketingName": "Golden Sun Banana" } ] }