356 lines
32 KiB
JavaScript
356 lines
32 KiB
JavaScript
import * as path from 'node:path';
|
|
import { hasMagic } from 'glob';
|
|
import { sync as dir } from '@polymech/fs/dir';
|
|
import { sync as exists } from '@polymech/fs/exists';
|
|
import { sync as write } from '@polymech/fs/write';
|
|
import { sync as read } from '@polymech/fs/read';
|
|
import { forward_slash, resolve, isFile, pathInfoEx } from '@polymech/commons';
|
|
import { isArray, isString } from '@polymech/core/primitives';
|
|
import { Logger } from 'tslog';
|
|
import { createClient } from '../client.js';
|
|
import { OptionsSchema } from '../zod_schema.js';
|
|
import { get, isWebUrl } from '../source.js';
|
|
import { flatten } from '../utils/array.js';
|
|
import { collector } from '../collector.js';
|
|
import { load as loadProfile } from '../profile.js';
|
|
import { load as loadTools } from '../tools.js';
|
|
import { preferences, prompt } from '../prompt.js';
|
|
import { variables } from '../variables.js';
|
|
import { E_Mode } from '../zod_schema.js';
|
|
import { runCompletion } from './run-completion.js';
|
|
import { runTools } from './run-tools.js';
|
|
import { runAssistant } from './run-assistant.js';
|
|
import { all } from '../models/index.js';
|
|
import { getLogger } from '../index.js';
|
|
import { lookup } from 'mime-types';
|
|
import { cwd as processCwd } from 'node:process';
|
|
export const default_sort = (files) => {
|
|
const getSortableParts = (filename) => {
|
|
const baseName = path.parse(filename).name;
|
|
const match = baseName.match(/^(\d+)_?(.*)$/); // Match leading numbers
|
|
const numPart = match ? parseInt(match[1], 10) : NaN;
|
|
const textPart = match ? match[2] : baseName; // Extract text part
|
|
return { numPart, textPart };
|
|
};
|
|
return files.sort((a, b) => {
|
|
const { numPart: aNum, textPart: aText } = getSortableParts(a);
|
|
const { numPart: bNum, textPart: bText } = getSortableParts(b);
|
|
if (!isNaN(aNum) && !isNaN(bNum)) {
|
|
return aNum - bNum || aText.localeCompare(bText, undefined, { numeric: true, sensitivity: 'base' });
|
|
}
|
|
return aText.localeCompare(bText, undefined, { numeric: true, sensitivity: 'base' });
|
|
});
|
|
};
|
|
/**
|
|
* Complete options by setting up defaults, validating inputs, and initializing required components
|
|
*
|
|
* @param opts - The initial task options
|
|
* @returns - The fully configured options object or null if validation fails
|
|
*/
|
|
export const complete_options = async (opts) => {
|
|
opts.logger = getLogger(opts);
|
|
const target = path.resolve(opts.output || opts.path || '.');
|
|
if (!exists(target)) {
|
|
dir(target);
|
|
}
|
|
opts.disable = flatten(opts.disable);
|
|
opts.disableTools = flatten(opts.disableTools);
|
|
opts.include = flatten(opts.include);
|
|
opts.exclude = flatten(opts.exclude || []);
|
|
opts.variables = opts.profile ? await loadProfile(opts) : {};
|
|
try {
|
|
const parsed = OptionsSchema().parse(opts);
|
|
const options = parsed;
|
|
const client = createClient(options);
|
|
if (!client) {
|
|
opts.logger.error('Failed to create client');
|
|
return null;
|
|
}
|
|
options.client = client;
|
|
options.variables = { ...options.variables, ...variables(options) };
|
|
options.collector = collector(options, client);
|
|
options.onRun = options.onRun || (async (options) => options);
|
|
return options;
|
|
}
|
|
catch (error) {
|
|
opts.logger.error('Failed to parse options:', error.message, error.issues);
|
|
return null;
|
|
}
|
|
};
|
|
/**
|
|
* Gather all messages from various sources for the task
|
|
*
|
|
* @param opts - The task options
|
|
* @param options - The completed options
|
|
* @returns - Array of messages and source files
|
|
*/
|
|
export const complete_messages = async (opts, options) => {
|
|
let messages = [];
|
|
const promptMessage = await prompt(opts);
|
|
if (!promptMessage?.content) {
|
|
return { messages: [], files: [] };
|
|
}
|
|
messages.push(promptMessage);
|
|
messages.push((await preferences(opts)));
|
|
// Get content from files and web URLs
|
|
let files = await get(path.resolve(options.path || '.'), options.include, options) || [];
|
|
files = files.map(f => {
|
|
if (f.path && f.content && typeof f.content === 'string') {
|
|
const mimeType = lookup(f.path);
|
|
// Check if the mime type is not binary (heuristic: starts with 'text/' or is a common non-binary type)
|
|
if (mimeType && (mimeType.startsWith('text/') || ['application/json', 'application/xml', 'application/javascript', 'application/typescript'].includes(mimeType))) {
|
|
if (options.wrap === 'meta') {
|
|
const absolutePath = path.resolve(options.path || '.', f.path);
|
|
const relativePath = f.path; // f.path is already relative from the get() function
|
|
const currentWorkingDirectory = processCwd();
|
|
const metaHeader = `IMPORTANT: The following information is file metadata. Please remove this entire block (from METADATA_START to METADATA_END) before processing the file content.
|
|
METADATA_START
|
|
File: ${relativePath}
|
|
Absolute Path: ${absolutePath}
|
|
CWD: ${currentWorkingDirectory}
|
|
METADATA_END
|
|
|
|
Original Content:
|
|
`;
|
|
return { ...f, content: metaHeader + f.content, role: 'user' };
|
|
}
|
|
else {
|
|
return { ...f, role: 'user' };
|
|
}
|
|
}
|
|
}
|
|
return { ...f, role: 'user' };
|
|
});
|
|
messages = [...messages, ...files];
|
|
return { messages, files };
|
|
};
|
|
/**
|
|
* Create and configure the parameters for the request
|
|
*
|
|
* @param options - The completed options
|
|
* @param messages - The gathered messages
|
|
* @returns - The configured parameters for the API request
|
|
*/
|
|
export const complete_params = async (options, messages) => {
|
|
const params = {
|
|
model: options.model,
|
|
messages,
|
|
tools: []
|
|
};
|
|
if (options.mode === E_Mode.TOOLS || options.mode === E_Mode.ASSISTANT) {
|
|
params.tools = await loadTools(options);
|
|
params.tool_choice = 'auto';
|
|
//params.parallel_tool_calls = false
|
|
}
|
|
return params;
|
|
};
|
|
/**
|
|
* Execute the request based on the mode and return the result
|
|
*
|
|
* @param options - The completed options
|
|
* @param client - The API client
|
|
* @param params - The request parameters
|
|
* @returns - The result of the execution
|
|
*/
|
|
export const execute_request = async (options, client, params) => {
|
|
let ret = null;
|
|
try {
|
|
switch (options.mode) {
|
|
case E_Mode.COMPLETION:
|
|
ret = await runCompletion(client, params, options);
|
|
break;
|
|
case E_Mode.TOOLS:
|
|
ret = await runTools(client, params, options);
|
|
break;
|
|
case E_Mode.ASSISTANT:
|
|
ret = await runAssistant(client, params, options);
|
|
break;
|
|
default:
|
|
throw new Error(`Unsupported mode: ${options.mode}`);
|
|
}
|
|
}
|
|
catch (e) {
|
|
options.logger?.error(`Error running ${options.mode} mode: ${e.message}`);
|
|
}
|
|
return ret;
|
|
};
|
|
/**
|
|
* Process a task with the configured options and return the result
|
|
*
|
|
* @param opts - The task options
|
|
* @returns - The result of the task execution
|
|
*/
|
|
export const processRun = async (opts) => {
|
|
let options = await complete_options(opts);
|
|
if (!options) {
|
|
return null;
|
|
}
|
|
const client = options.client;
|
|
const { messages, files } = await complete_messages(opts, options);
|
|
if (messages.length === 0) {
|
|
return "";
|
|
}
|
|
const params = await complete_params(options, messages);
|
|
const logDir = path.resolve(resolve(opts.logs || './logs'));
|
|
const paramsPath = path.join(logDir, 'params.json');
|
|
write(paramsPath, JSON.stringify({ ...params }, null, 2));
|
|
if (opts.mode === E_Mode.TOOLS) {
|
|
options.logger.debug(`kbot run ${options.mode} : ${options.model} @ ${options.router} : ${files.length} files from project ${path.resolve(options.path || '.')} with ${options.include}`, files.map(f => f.path), params.tools.map(t => `${t.function.name} : ${t.function.description}`));
|
|
}
|
|
else {
|
|
options.logger.debug(`kbot run ${options.mode} : ${options.model} @ ${options.router} : ${files.length} files from project ${path.resolve(options.path || '.')} with ${options.include}`, files.map(f => f.path));
|
|
}
|
|
options = await options.onRun(options) || options;
|
|
const ret = await execute_request(options, client, params);
|
|
return ret;
|
|
};
|
|
/**
|
|
* Extract file paths (Windows or POSIX style) from a single string,
|
|
* preserving any spaces within the paths. Needed for Salamand File Manager selections (eg: kbot "summarize, as json" -i "$(ListOfSelectedFullNames)")
|
|
* - For Windows, it looks for patterns like "C:\" (any drive letter).
|
|
* - For POSIX, it looks for a leading slash "/".
|
|
* - For web URLs, it looks for patterns like "http://" or "https://".
|
|
*
|
|
* Returns an array of path strings. If no matches are found, returns [].
|
|
*
|
|
*/
|
|
function extractPaths(input) {
|
|
// If it's a web URL, return it
|
|
if (isWebUrl(input)) {
|
|
return [input];
|
|
}
|
|
// If it's a direct path that exists, return it
|
|
if (exists(path.resolve(resolve(input)))) {
|
|
return [input];
|
|
}
|
|
// If it's a glob pattern, return it as is
|
|
if (hasMagic(input)) {
|
|
return [input];
|
|
}
|
|
// Matches either a Windows drive pattern like "C:\", a forward slash "/", or http/https URLs
|
|
const pathStartRegex = /([A-Za-z]:\\)|\/|(https?:\/\/)/g;
|
|
const matchIndices = [];
|
|
let match;
|
|
// Collect the start index of each path
|
|
while ((match = pathStartRegex.exec(input)) !== null) {
|
|
matchIndices.push(match.index);
|
|
}
|
|
// If none found, return empty
|
|
if (!matchIndices.length) {
|
|
return [];
|
|
}
|
|
// Slice from each index to just before the next
|
|
const paths = [];
|
|
for (let i = 0; i < matchIndices.length; i++) {
|
|
const start = matchIndices[i];
|
|
const end = i < matchIndices.length - 1 ? matchIndices[i + 1] : input.length;
|
|
const path = input.substring(start, end).trim();
|
|
if (path) {
|
|
paths.push(path);
|
|
}
|
|
}
|
|
return paths;
|
|
}
|
|
function flattenArrays(arrays) {
|
|
return arrays.reduce((accumulator, current) => {
|
|
return accumulator.concat(current);
|
|
}, []);
|
|
}
|
|
export const run = async (opts) => {
|
|
const ret = [];
|
|
const logger = new Logger({ minLevel: opts.logLevel || 2 });
|
|
opts.logger = logger;
|
|
if (opts.include) {
|
|
if (isString(opts.include)) {
|
|
opts.include = [opts.include];
|
|
}
|
|
if (isArray(opts.include)) {
|
|
// First check for glob patterns and web URLs
|
|
const specialPatterns = opts.include.filter((path) => hasMagic(path) || isWebUrl(path));
|
|
// Then process normal paths
|
|
const normalPaths = opts.include.filter((path) => !hasMagic(path) && !isWebUrl(path));
|
|
const processedPaths = flattenArrays(normalPaths.map(extractPaths));
|
|
// Combine special patterns and processed paths
|
|
opts.include = [...specialPatterns, ...processedPaths];
|
|
}
|
|
}
|
|
else {
|
|
opts.include = [];
|
|
}
|
|
// Process opts.exclude similarly to opts.include
|
|
if (opts.exclude) {
|
|
if (isString(opts.exclude)) {
|
|
opts.exclude = [opts.exclude];
|
|
}
|
|
if (isArray(opts.exclude)) {
|
|
const specialPatterns = opts.exclude.filter((path) => hasMagic(path) || isWebUrl(path));
|
|
const normalPaths = opts.exclude.filter((path) => !hasMagic(path) && !isWebUrl(path));
|
|
const processedPaths = flattenArrays(normalPaths.map(extractPaths));
|
|
opts.exclude = [...specialPatterns, ...processedPaths];
|
|
}
|
|
}
|
|
else {
|
|
opts.exclude = [];
|
|
}
|
|
if (opts.each) {
|
|
let items = [];
|
|
if (isArray(opts.each)) {
|
|
items = opts.each;
|
|
}
|
|
else if (exists(opts.each) && isFile(opts.each) && path.parse(opts.each).ext === '.json') {
|
|
items = read(opts.each, 'json') || [];
|
|
}
|
|
else if (hasMagic(opts.each)) {
|
|
const info = pathInfoEx(forward_slash(path.resolve(resolve(opts.each))), false, {
|
|
absolute: true,
|
|
});
|
|
items = default_sort(info.FILES);
|
|
}
|
|
else if (isFile(opts.each) && exists(opts.each)) {
|
|
items = [opts.each];
|
|
}
|
|
else if (isString(opts.each)) {
|
|
items = opts.each.split(',');
|
|
}
|
|
if (items.length === 0) {
|
|
opts.logger.warn(`No files matching pattern ${opts.each} found in ${opts.path}`);
|
|
return ret;
|
|
}
|
|
opts.logger.info(`Processing ${items.length} items matching pattern ${opts.each}...`);
|
|
const _models = all();
|
|
for (const item of items) {
|
|
const itemOpts = {
|
|
...opts,
|
|
ITEM: item,
|
|
variables: { ITEM: item }
|
|
};
|
|
//override model if item is a model id
|
|
const model = _models.find(m => m.id === item);
|
|
if (model) {
|
|
itemOpts.model = item;
|
|
}
|
|
let currentItemSpecificIncludes = [forward_slash(item)];
|
|
const itemPathInfo = path.parse(item);
|
|
// Only add corresponding .cpp if --glob-extension=match-cpp is set
|
|
if (opts.globExtension === 'match-cpp' && itemPathInfo.ext === '.h') {
|
|
const cppFilePath = path.join(itemPathInfo.dir, `${itemPathInfo.name}.cpp`);
|
|
if (exists(cppFilePath) && isFile(cppFilePath)) {
|
|
currentItemSpecificIncludes.push(forward_slash(cppFilePath));
|
|
}
|
|
}
|
|
itemOpts.include = [...opts.include, ...currentItemSpecificIncludes];
|
|
const result = await processRun(itemOpts);
|
|
if (result !== undefined) {
|
|
ret.push(result);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
const result = await processRun(opts);
|
|
if (result !== undefined) {
|
|
ret.push(result);
|
|
}
|
|
}
|
|
return ret;
|
|
};
|
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL3J1bi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssSUFBSSxNQUFNLFdBQVcsQ0FBQTtBQUNqQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sTUFBTSxDQUFBO0FBQy9CLE9BQU8sRUFBRSxJQUFJLElBQUksR0FBRyxFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFDOUMsT0FBTyxFQUFFLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUNwRCxPQUFPLEVBQUUsSUFBSSxJQUFJLEtBQUssRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBQ2xELE9BQU8sRUFBRSxJQUFJLElBQUksSUFBSSxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDaEQsT0FBTyxFQUFFLGFBQWEsRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQzlFLE9BQU8sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sMkJBQTJCLENBQUE7QUFLN0QsT0FBTyxFQUFFLE1BQU0sRUFBVyxNQUFNLE9BQU8sQ0FBQTtBQUN2QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sY0FBYyxDQUFBO0FBQzNDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUNoRCxPQUFPLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBRSxNQUFNLGNBQWMsQ0FBQTtBQUM1QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDM0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBQzNDLE9BQU8sRUFBRSxJQUFJLElBQUksV0FBVyxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ25ELE9BQU8sRUFBRSxJQUFJLElBQUksU0FBUyxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQy9DLE9BQU8sRUFB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QUE7SUFDbkQsS0FBSyxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsR0FBRyxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUN6RCxJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQy9CLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLFlBQVksT0FBTyxDQUFDLElBQUksTUFBTSxPQUFPLENBQUMsS0FBSyxNQUFNLE9BQU8sQ0FBQyxNQUFNLE9BQU8sS0FBSyxDQUFDLE1BQU0sdUJBQXVCLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksSUFBSSxHQUFHLENBQUMsU0FBUyxPQUFPLENBQUMsT0FBTyxFQUFFLEVBQUUsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLFFBQVEsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDLENBQUE7SUFDN1IsQ0FBQztTQUFNLENBQUM7UUFDTixPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxZQUFZLE9BQU8sQ0FBQyxJQUFJLE1BQU0sT0FBTyxDQUFDLEtBQUssTUFBTSxPQUFPLENBQUMsTUFBTSxPQUFPLEtBQUssQ0FBQyxNQUFNLHVCQUF1QixJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLElBQUksR0FBRyxDQUFDLFNBQVMsT0FBTyxDQUFDLE9BQU8sRUFBRSxFQUFFLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQTtJQUNwTixDQUFDO0lBQ0QsT0FBTyxHQUFHLE1BQU0sT0FBTyxDQUFDLEtBQUssQ0FB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
|