init
This commit is contained in:
138
src/tools.ts
Normal file
138
src/tools.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
import {$, $Sync} from '@ztimson/node-utils';
|
||||
import {ASet, consoleInterceptor, Http, fn as Fn} from '@ztimson/utils';
|
||||
import {Ai} from './ai.ts';
|
||||
|
||||
export type AiToolArg = {[key: string]: {
|
||||
/** Argument type */
|
||||
type: 'array' | 'boolean' | 'number' | 'object' | 'string',
|
||||
/** Argument description */
|
||||
description: string,
|
||||
/** Required argument */
|
||||
required?: boolean;
|
||||
/** Default value */
|
||||
default?: any,
|
||||
/** Options */
|
||||
enum?: string[],
|
||||
/** Minimum value or length */
|
||||
min?: number,
|
||||
/** Maximum value or length */
|
||||
max?: number,
|
||||
/** Match pattern */
|
||||
pattern?: string,
|
||||
/** Child arguments */
|
||||
items?: {[key: string]: AiToolArg}
|
||||
}}
|
||||
|
||||
export type AiTool = {
|
||||
/** Tool ID / Name - Must be snail_case */
|
||||
name: string,
|
||||
/** Tool description / prompt */
|
||||
description: string,
|
||||
/** Tool arguments */
|
||||
args?: AiToolArg,
|
||||
/** Callback function */
|
||||
fn: (args: any, ai: Ai) => any | Promise<any>,
|
||||
};
|
||||
|
||||
export const CliTool: AiTool = {
|
||||
name: 'cli',
|
||||
description: 'Use the command line interface, returns any output',
|
||||
args: {command: {type: 'string', description: 'Command to run', required: true}},
|
||||
fn: (args: {command: string}) => $`${args.command}`
|
||||
}
|
||||
|
||||
export const DateTimeTool: AiTool = {
|
||||
name: 'get_datetime',
|
||||
description: 'Get current date and time',
|
||||
args: {},
|
||||
fn: async () => new Date().toISOString()
|
||||
}
|
||||
|
||||
export const ExecTool: AiTool = {
|
||||
name: 'exec',
|
||||
description: 'Run code/scripts',
|
||||
args: {
|
||||
language: {type: 'string', description: 'Execution language', enum: ['cli', 'node', 'python'], required: true},
|
||||
code: {type: 'string', description: 'Code to execute', required: true}
|
||||
},
|
||||
fn: async (args, ai) => {
|
||||
try {
|
||||
switch(args.type) {
|
||||
case 'bash':
|
||||
return await CliTool.fn({command: args.code}, ai);
|
||||
case 'node':
|
||||
return await JSTool.fn({code: args.code}, ai);
|
||||
case 'python': {
|
||||
return await PythonTool.fn({code: args.code}, ai);
|
||||
}
|
||||
}
|
||||
} catch(err: any) {
|
||||
return {error: err?.message || err.toString()};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const FetchTool: AiTool = {
|
||||
name: 'fetch',
|
||||
description: 'Make HTTP request to URL',
|
||||
args: {
|
||||
url: {type: 'string', description: 'URL to fetch', required: true},
|
||||
method: {type: 'string', description: 'HTTP method to use', enum: ['GET', 'POST', 'PUT', 'DELETE'], default: 'GET'},
|
||||
headers: {type: 'object', description: 'HTTP headers to send', default: {}},
|
||||
body: {type: 'object', description: 'HTTP body to send'},
|
||||
},
|
||||
fn: (args: {
|
||||
url: string;
|
||||
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
||||
headers: {[key: string]: string};
|
||||
body: any;
|
||||
}) => new Http({url: args.url, headers: args.headers}).request({method: args.method || 'GET', body: args.body})
|
||||
}
|
||||
|
||||
export const JSTool: AiTool = {
|
||||
name: 'exec_javascript',
|
||||
description: 'Execute commonjs javascript',
|
||||
args: {
|
||||
code: {type: 'string', description: 'CommonJS javascript', required: true}
|
||||
},
|
||||
fn: async (args: {code: string}) => {
|
||||
const console = consoleInterceptor(null);
|
||||
const resp = await Fn<any>({console}, args.code, true).catch((err: any) => console.output.error.push(err));
|
||||
return {...console.output, return: resp, stdout: undefined, stderr: undefined};
|
||||
}
|
||||
}
|
||||
|
||||
export const PythonTool: AiTool = {
|
||||
name: 'exec_javascript',
|
||||
description: 'Execute commonjs javascript',
|
||||
args: {
|
||||
code: {type: 'string', description: 'CommonJS javascript', required: true}
|
||||
},
|
||||
fn: async (args: {code: string}) => ({result: $Sync`python -c "${args.code}"`})
|
||||
}
|
||||
|
||||
export const SearchTool: AiTool = {
|
||||
name: 'search',
|
||||
description: 'Use a search engine to find relevant URLs, should be changed with fetch to scrape sources',
|
||||
args: {
|
||||
query: {type: 'string', description: 'Search string', required: true},
|
||||
length: {type: 'string', description: 'Number of results to return', default: 5},
|
||||
},
|
||||
fn: async (args: {
|
||||
query: string;
|
||||
length: number;
|
||||
}) => {
|
||||
const html = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(args.query)}`, {
|
||||
headers: {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "Accept-Language": "en-US,en;q=0.9"}
|
||||
}).then(resp => resp.text());
|
||||
let match, regex = /<a .*?href="(.+?)".+?<\/a>/g;
|
||||
const results = new ASet<string>();
|
||||
while((match = regex.exec(html)) !== null) {
|
||||
let url = /uddg=(.+)&?/.exec(decodeURIComponent(match[1]))?.[1];
|
||||
if(url) url = decodeURIComponent(url);
|
||||
if(url) results.add(url);
|
||||
if(results.size >= (args.length || 5)) break;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user