@just-every/ensemble
Version:
LLM provider abstraction layer with unified streaming interface
187 lines • 7.41 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.createToolFunction = createToolFunction;
const validToolParameterTypes = ['string', 'number', 'boolean', 'array', 'object', 'null'];
function createToolFunction(func, description, paramMap, returns, functionName) {
const funcStr = func.toString();
const funcName = (functionName || '').replaceAll(' ', '_') || func.name;
if (!funcName) {
throw new Error('[createToolFunction] Function name is required');
}
let toolDescription = description || `Tool for ${funcName}`;
if (returns) {
toolDescription += ` Returns: ${returns}`;
}
const cleanFuncStr = funcStr.replaceAll(/\n\s*/g, ' ');
const paramMatch = cleanFuncStr.match(/\(([^)]*)\)/);
const properties = {};
const required = [];
let injectAgentId = false;
let injectAbortSignal = false;
const params = paramMap
? Object.keys(paramMap)
: paramMatch && paramMatch[1]
? paramMatch[1]
.split(',')
.map(p => p.trim())
.filter(Boolean)
: [];
for (const paramUnknown of params) {
if (typeof paramUnknown !== 'string') {
console.warn(`Skipping non-string parameter in function signature analysis: ${paramUnknown}`);
continue;
}
const param = paramUnknown;
const paramParts = param.split('=').map(p => p.trim());
let paramName = paramParts[0].trim();
const defaultValue = paramParts.length > 1 ? paramParts[1].trim() : undefined;
if (paramName.includes(':')) {
paramName = paramName.split(':')[0].trim();
}
const isRestParam = paramName.startsWith('...');
const cleanParamName = isRestParam ? paramName.substring(3) : paramName;
if (cleanParamName === 'inject_agent_id') {
injectAgentId = true;
continue;
}
if (cleanParamName === 'abort_signal') {
injectAbortSignal = true;
continue;
}
const paramInfoRaw = paramMap?.[cleanParamName];
let paramInfoObj = undefined;
let paramInfoDesc = undefined;
if (typeof paramInfoRaw === 'string') {
paramInfoDesc = paramInfoRaw;
paramInfoObj = { type: 'string', description: paramInfoRaw };
}
else if (typeof paramInfoRaw === 'object' && paramInfoRaw !== null) {
paramInfoObj = paramInfoRaw;
paramInfoDesc =
typeof paramInfoRaw.description === 'function' ? paramInfoRaw.description() : paramInfoRaw.description;
}
const apiParamName = cleanParamName;
let paramType = 'string';
if (paramInfoObj?.type && validToolParameterTypes.includes(paramInfoObj.type)) {
paramType = paramInfoObj.type;
}
else if (isRestParam) {
paramType = 'array';
}
else if (defaultValue !== undefined) {
if (defaultValue === 'false' || defaultValue === 'true') {
paramType = 'boolean';
}
else if (!isNaN(Number(defaultValue)) && !defaultValue.startsWith('"') && !defaultValue.startsWith("'")) {
paramType = 'number';
}
else if (defaultValue === '[]' || defaultValue.startsWith('[')) {
paramType = 'array';
}
else if (defaultValue === '{}' || defaultValue.startsWith('{')) {
paramType = 'object';
}
}
const finalDescription = paramInfoDesc || `The ${cleanParamName} parameter`;
const paramDef = {
type: paramType,
description: finalDescription,
};
if (paramType === 'array') {
if (paramInfoObj?.items) {
paramDef.items = paramInfoObj.items;
}
else {
paramDef.items = {
type: 'string',
};
}
}
if (paramType === 'object') {
if (paramInfoObj?.properties) {
paramDef.properties = paramInfoObj.properties;
}
else {
throw new Error(`[createToolFunction] Parameter '${cleanParamName}' is of type 'object' but has no 'properties' defined. ` +
`Object parameters must define their structure when used with strict mode. ` +
`Either provide a 'properties' field or use a different type like 'string' for JSON data.`);
}
if (paramInfoObj?.required) {
paramDef.required = paramInfoObj.required;
}
}
if (paramInfoObj?.enum) {
if (typeof paramInfoObj.enum === 'function') {
const enumFn = paramInfoObj.enum;
const fnStr = enumFn.toString();
const isAsync = fnStr.includes('__awaiter') ||
fnStr.startsWith('async ') ||
enumFn.constructor.name === 'AsyncFunction';
if (isAsync) {
paramDef.enum = enumFn;
}
else {
paramDef.enum = enumFn();
}
}
else {
paramDef.enum = paramInfoObj.enum;
}
}
if (paramInfoObj?.minimum !== undefined) {
paramDef.minimum = paramInfoObj.minimum;
}
if (paramInfoObj?.maximum !== undefined) {
paramDef.maximum = paramInfoObj.maximum;
}
if (paramInfoObj?.default !== undefined) {
paramDef.default = paramInfoObj.default;
}
else if (defaultValue !== undefined) {
paramDef.default = defaultValue;
}
if (paramInfoObj?.minLength !== undefined) {
paramDef.minLength = paramInfoObj.minLength;
}
if (paramInfoObj?.maxLength !== undefined) {
paramDef.maxLength = paramInfoObj.maxLength;
}
if (paramInfoObj?.pattern !== undefined) {
paramDef.pattern = paramInfoObj.pattern;
}
if (paramInfoObj?.minItems !== undefined) {
paramDef.minItems = paramInfoObj.minItems;
}
if (paramInfoObj?.additionalProperties !== undefined) {
paramDef.additionalProperties = paramInfoObj.additionalProperties;
}
properties[apiParamName] = paramDef;
if (paramDef.default === undefined && !paramInfoObj?.optional) {
required.push(apiParamName);
}
}
if (!injectAgentId && /\(\s*[^)]*\binject_agent_id\b/.test(funcStr)) {
injectAgentId = true;
}
if (!injectAbortSignal && /\(\s*[^)]*\babort_signal\b/.test(funcStr)) {
injectAbortSignal = true;
}
return {
function: func,
definition: {
type: 'function',
function: {
name: funcName,
description: toolDescription,
parameters: {
type: 'object',
properties,
required: required.length > 0 ? required : undefined,
},
},
},
...(injectAgentId && { injectAgentId }),
...(injectAbortSignal && { injectAbortSignal }),
};
}
//# sourceMappingURL=create_tool_function.js.map
;