helpingai
Version:
The official JavaScript/TypeScript library for the HelpingAI API - Advanced AI with Emotional Intelligence
217 lines • 8.19 kB
JavaScript
;
/**
* Base class for built-in tools inspired by Qwen-Agent.
*
* This module provides the base infrastructure for implementing built-in tools
* that are compatible with the HelpingAI tools framework.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BuiltinToolBase = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const url_1 = require("url");
const errors_1 = require("../../errors");
/**
* Base class for built-in tools.
*
* This class provides common functionality for built-in tools including
* file handling, parameter validation, and integration with HelpingAI's tool framework.
*/
class BuiltinToolBase {
constructor(config = {}) {
this.config = config;
// Set up working directory - use a default name for now
const defaultWorkDir = path.join(os.tmpdir(), 'helpingai_tools', 'builtin_tool');
this.workDir = this.config.workDir || defaultWorkDir;
// Create working directory if it doesn't exist
this.ensureWorkDir();
}
/**
* Initialize the tool after construction (called by subclasses)
*/
initialize() {
// Update work directory with actual tool name
if (!this.config.workDir) {
this.workDir = path.join(os.tmpdir(), 'helpingai_tools', this.name);
this.ensureWorkDir();
}
if (!this.name) {
throw new Error(`Tool class ${this.constructor.name} must define a 'name' property`);
}
if (!this.description) {
throw new Error(`Tool class ${this.constructor.name} must define a 'description' property`);
}
}
/**
* Convert this built-in tool to a function that can be used with HelpingAI's tool framework.
*
* @returns Function that can be executed
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
toFunction() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return async (kwargs) => {
try {
return await this.execute(kwargs);
}
catch (error) {
throw new errors_1.ToolExecutionError(`Failed to execute built-in tool '${this.name}': ${error instanceof Error ? error.message : String(error)}`, this.name);
}
};
}
/**
* Get tool definition in OpenAI format
*/
getToolDefinition() {
return {
type: 'function',
function: {
name: this.name,
description: this.description,
parameters: this.parameters,
},
};
}
/**
* Validate tool parameters against schema.
*
* @param params - Parameters to validate
* @throws Error if validation fails
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
validateParameters(params) {
// Check required parameters
const requiredParams = this.parameters.required || [];
for (const param of requiredParams) {
if (!(param in params)) {
throw new Error(`Missing required parameter '${param}' for tool '${this.name}'`);
}
}
// Check for unknown parameters
const allowedParams = new Set(Object.keys(this.parameters.properties || {}));
const providedParams = new Set(Object.keys(params));
const unknownParams = [...providedParams].filter(p => !allowedParams.has(p));
if (unknownParams.length > 0) {
throw new Error(`Unknown parameters for tool '${this.name}': ${unknownParams.join(', ')}`);
}
}
/**
* Ensure working directory exists
*/
ensureWorkDir() {
try {
if (!fs.existsSync(this.workDir)) {
fs.mkdirSync(this.workDir, { recursive: true });
}
}
catch (error) {
throw new Error(`Failed to create working directory ${this.workDir}: ${error}`);
}
}
/**
* Download a file from URL to working directory.
*
* @param url - URL to download from
* @param filename - Optional filename, will be inferred from URL if not provided
* @returns Path to downloaded file
* @throws ToolExecutionError if download fails
*/
async downloadFile(url, filename) {
try {
const fetch = (await Promise.resolve().then(() => __importStar(require('cross-fetch')))).default;
if (!filename) {
const parsedUrl = new url_1.URL(url);
filename = path.basename(parsedUrl.pathname) || 'downloaded_file';
}
const filePath = path.join(this.workDir, filename);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const buffer = await response.arrayBuffer();
fs.writeFileSync(filePath, Buffer.from(buffer));
return filePath;
}
catch (error) {
throw new errors_1.ToolExecutionError(`Failed to download file from ${url}: ${error instanceof Error ? error.message : String(error)}`, this.name);
}
}
/**
* Read file content as text.
*
* @param filePath - Path to file or URL
* @returns File content as string
* @throws ToolExecutionError if reading fails
*/
async readFile(filePath) {
try {
if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
// Download the file first
const localPath = await this.downloadFile(filePath);
filePath = localPath;
}
return fs.readFileSync(filePath, 'utf-8');
}
catch (error) {
throw new errors_1.ToolExecutionError(`Failed to read file ${filePath}: ${error instanceof Error ? error.message : String(error)}`, this.name);
}
}
/**
* Write content to file in working directory.
*
* @param content - Content to write
* @param filename - Filename
* @returns Path to written file
* @throws ToolExecutionError if writing fails
*/
writeFile(content, filename) {
try {
const filePath = path.join(this.workDir, filename);
fs.writeFileSync(filePath, content, 'utf-8');
return filePath;
}
catch (error) {
throw new errors_1.ToolExecutionError(`Failed to write file ${filename}: ${error instanceof Error ? error.message : String(error)}`, this.name);
}
}
/**
* Clean up the working directory.
*/
cleanupWorkDir() {
try {
if (fs.existsSync(this.workDir)) {
fs.rmSync(this.workDir, { recursive: true, force: true });
}
}
catch (error) {
// Ignore cleanup errors
console.warn(`Failed to cleanup work directory: ${error}`);
}
}
}
exports.BuiltinToolBase = BuiltinToolBase;
//# sourceMappingURL=base.js.map