@just-every/ensemble
Version:
LLM provider abstraction layer with unified streaming interface
168 lines • 6.21 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.coerceValue = coerceValue;
exports.extractParameterNames = extractParameterNames;
exports.mapNamedToPositionalArgs = mapNamedToPositionalArgs;
function coerceValue(value, paramSpec, paramName) {
const expectedType = paramSpec.type || 'string';
if (value === undefined || value === null) {
if (paramSpec.default) {
return [paramSpec.default, null];
}
if (paramSpec.optional) {
return [undefined, null];
}
return [null, `Required parameter "${paramName}" is missing`];
}
if (value === '' && paramSpec.optional) {
return [undefined, null];
}
const actualType = Array.isArray(value) ? 'array' : typeof value;
switch (expectedType) {
case 'string':
if (actualType === 'string') {
return [value, null];
}
return [String(value), null];
case 'number':
if (actualType === 'number') {
return [value, null];
}
if (actualType === 'string') {
const num = Number(value);
if (!isNaN(num)) {
return [num, null];
}
return [null, `Cannot convert "${value}" to number`];
}
return [null, `Expected number but got ${actualType}`];
case 'boolean':
if (actualType === 'boolean') {
return [value, null];
}
if (actualType === 'string') {
const lower = value.toLowerCase();
if (lower === 'true')
return [true, null];
if (lower === 'false')
return [false, null];
return [null, `Cannot convert "${value}" to boolean`];
}
if (actualType === 'number') {
return [value !== 0, null];
}
return [null, `Expected boolean but got ${actualType}`];
case 'array':
if (actualType === 'array') {
return [value, null];
}
if (actualType === 'string') {
try {
const parsed = JSON.parse(value);
if (Array.isArray(parsed)) {
return [parsed, null];
}
}
catch {
if (value.includes(',')) {
return [value.split(',').map(s => s.trim()), null];
}
}
return [[value], null];
}
return [[value], null];
case 'object':
if (actualType === 'object' && !Array.isArray(value)) {
return [value, null];
}
if (actualType === 'string') {
try {
const parsed = JSON.parse(value);
if (typeof parsed === 'object' && !Array.isArray(parsed)) {
return [parsed, null];
}
}
catch {
return [null, `Cannot parse "${value}" as object`];
}
}
return [null, `Expected object but got ${actualType}`];
case 'null':
return [null, null];
default:
return [value, null];
}
}
function extractParameterNames(func) {
const funcStr = func.toString();
const cleanFuncStr = funcStr.replaceAll(/\n\s*/g, ' ');
const paramMatch = cleanFuncStr.match(/\(([^)]*)\)/);
if (!paramMatch || !paramMatch[1]) {
return [];
}
const params = paramMatch[1]
.split(',')
.map(p => p.trim())
.filter(Boolean);
const paramNames = [];
for (const param of params) {
let paramName = param;
if (paramName.includes('=')) {
paramName = paramName.split('=')[0].trim();
}
if (paramName.includes(':')) {
paramName = paramName.split(':')[0].trim();
}
if (paramName.startsWith('...')) {
paramName = paramName.substring(3);
}
if (paramName === 'inject_agent_id' || paramName === 'abort_signal') {
continue;
}
paramNames.push(paramName);
}
return paramNames;
}
function mapNamedToPositionalArgs(namedArgs, tool, injectAgentId, abortSignal) {
const paramNames = extractParameterNames(tool.function);
const paramSpecs = tool.definition.function.parameters.properties || {};
const requiredParams = tool.definition.function.parameters.required || [];
Object.keys(namedArgs).forEach(key => {
if (!paramNames.includes(key)) {
console.warn(`Removing unknown parameter "${key}" for tool "${tool.definition.function.name}"`);
delete namedArgs[key];
}
});
const positionalArgs = [];
for (const paramName of paramNames) {
const value = namedArgs[paramName];
const paramSpec = paramSpecs[paramName] || { type: 'string' };
if ((value === undefined || value === '') && !requiredParams.includes(paramName)) {
positionalArgs.push(undefined);
continue;
}
const [coercedValue, error] = coerceValue(value, paramSpec, paramName);
if (error && requiredParams.includes(paramName)) {
throw new Error(JSON.stringify({
error: {
param: paramName,
expected: paramSpec.type + (paramSpec.items?.type ? `<${paramSpec.items.type}>` : ''),
received: String(value),
message: error,
},
}));
}
else if (error) {
console.warn(`Parameter coercion warning for ${paramName}: ${error}`);
}
positionalArgs.push(coercedValue);
}
if (tool.injectAgentId && injectAgentId) {
positionalArgs.unshift(injectAgentId);
}
if (tool.injectAbortSignal && abortSignal) {
positionalArgs.push(abortSignal);
}
return positionalArgs;
}
//# sourceMappingURL=tool_parameter_utils.js.map
;