173 lines
15 KiB
JavaScript
173 lines
15 KiB
JavaScript
import { defaultError, defaultFilters, testFilters, transformObjectWithOptions, DEFAULT_NETWORK_OPTIONS } 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;
|
|
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 obj;
|
|
};
|
|
const DEFAULT_CACHE_CONFIG = {
|
|
enabled: true,
|
|
namespace: 'llm-responses',
|
|
expiration: 7 * 24 * 60 * 60 // 7 days in seconds
|
|
};
|
|
export function createLLMTransformer(options, logger = dummyLogger, cacheConfig) {
|
|
const config = { ...DEFAULT_CACHE_CONFIG, ...cacheConfig };
|
|
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}"`,
|
|
};
|
|
const cacheKeyObj = removeEmptyObjects({
|
|
prompt: kbotTask.prompt,
|
|
model: kbotTask.model,
|
|
router: kbotTask.router,
|
|
mode: kbotTask.mode,
|
|
filters: [],
|
|
tools: []
|
|
});
|
|
try {
|
|
if (config.enabled) {
|
|
const cachedResponse = await get_cached_object({ ca_options: cacheKeyObj }, config.namespace);
|
|
if (cachedResponse?.content) {
|
|
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();
|
|
if (config.enabled) {
|
|
await set_cached_object({ ca_options: cacheKeyObj }, config.namespace, { content: result }, { expiration: config.expiration });
|
|
logger.info(`Cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`);
|
|
}
|
|
logger.info(`Result: ${result}`);
|
|
return result;
|
|
}
|
|
logger.warn(`No valid result received for ${jsonPath}, returning original`);
|
|
return input;
|
|
}
|
|
catch (error) {
|
|
logger.error(`Error calling LLM API: ${error.message}`, error);
|
|
return input;
|
|
}
|
|
};
|
|
}
|
|
export function createIterator(obj, optionsMixin, globalOptions = {}) {
|
|
const { network = {}, errorCallback = defaultError, filterCallback = testFilters(defaultFilters()), transformerFactory, logger = dummyLogger, cacheConfig, onTransform, onTransformed } = globalOptions;
|
|
const networkOptions = {
|
|
...DEFAULT_NETWORK_OPTIONS,
|
|
...network
|
|
};
|
|
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 } = mapping;
|
|
const transformer = createTransformer(mergedOptions);
|
|
await transformObjectWithOptions(transformedObj, transformer, {
|
|
jsonPath,
|
|
targetPath,
|
|
network: networkOptions,
|
|
errorCallback,
|
|
filterCallback,
|
|
onTransform,
|
|
onTransformed,
|
|
kbotOptions: mergedOptions
|
|
});
|
|
}
|
|
// 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);
|
|
}
|
|
};
|
|
}
|
|
export async function transformWithMappings(obj, createTransformer, mappings, globalOptions = {}) {
|
|
const iterator = createIterator(obj, {}, globalOptions);
|
|
await iterator.transform(mappings);
|
|
}
|
|
/**
|
|
* Simplified transformation function that only requires the target object and field mappings.
|
|
* All other options are optional with sensible defaults.
|
|
*
|
|
* @param obj - The object to transform
|
|
* @param mappings - Field mappings defining what to transform and how
|
|
* @param optionsMixin - Optional global options to apply to all transformations
|
|
* @param options - Optional advanced configuration
|
|
* @returns The transformed object (also modifies the original)
|
|
*/
|
|
export async function transform(obj, mappings, optionsMixin = {}, options = {}) {
|
|
const iterator = createIterator(obj, optionsMixin, options);
|
|
await iterator.transform(mappings);
|
|
return obj;
|
|
}
|
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXRlcmF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaXRlcmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQU1ILFlBQVksRUFDWixjQUFjLEVBQ2QsV0FBVyxFQUNYLDBCQUEwQixFQUUxQix1QkFBdUIsRUFDMUIsTUFBTSxxQkFBcUIsQ0FBQTtBQUM1QixPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDdkMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLGlCQUFpQixFQUFvQixNQUFNLGlCQUFpQixDQUFBO0FBaUJ4RixNQUFNLFdBQVcsR0FBWTtJQUN6QixJQUFJLEVBQUUsR0FBRyxFQUFFLEdBQUUsQ0FBQztJQUNkLElBQUksRUFBRSxHQUFHLEVBQUUsR0FBRSxDQUFDO0lBQ2QsS0FBSyxFQUFFLEdBQUcsRUFBRSxHQUFFLENBQUM7Q0FDbEIsQ0FBQztBQUVGLE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHLENBQUMsR0FBUSxFQUFPLEVBQUU7SUFDaEQsSUFBSSxHQUFHLEtBQUssSUFBSSxJQUFJLEdBQUcsS0FBSyxTQUFTO1FBQUUsT0FBTyxHQUFHLENBQUM7SUFDbEQsS0FBSyxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUNwQixNQUFNLEdBQUcsR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUE7UUFDcEIsSUFBSSxHQUFHLEtBQUssSUFBSSxJQUFJLEdBQUcsS0FBSyxTQUFTO1lBQUUsU0FBUztRQUNoRCxJQUFJLE9BQU8sR0FBRyxLQUFLLFFBQVE7WUFDdkIsQ0FBQyxHQUFHLElBQUksT0FBTyxJQUFJLE9BQU8sR0FBRyxLQUFLLFFBQVEsSUFBSSxHQUFHLEtBQUssQ0FBQyxJQUFJLEdBQUcsSUFBSSxRQUFRLENBQUMsRUFDN0UsQ0FBQztZQUNDLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMs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
|