node-llama-cpp
Version:
Run AI models locally on your machine with node.js bindings for llama.cpp. Enforce a JSON schema on the model output on the generation level
174 lines • 8 kB
JavaScript
import { getTypeScriptTypeStringForGbnfJsonSchema } from "../../utils/getTypeScriptTypeStringForGbnfJsonSchema.js";
import { jsonDumps } from "./jsonDumps.js";
/**
* Generate documentation about the functions that are available for a model to call.
* Useful for generating a system message with information about the available functions as part of a chat wrapper.
*/
export class ChatModelFunctionsDocumentationGenerator {
chatModelFunctions;
hasAnyFunctions;
constructor(chatModelFunctions) {
this.chatModelFunctions = chatModelFunctions;
this.hasAnyFunctions = Object.keys(this.chatModelFunctions ?? {}).length > 0;
}
/**
* Example:
* ```ts
* // Retrieve the current date
* function getDate();
*
* // Retrieve the current time
* function getTime(params: {hours: "24" | "12", seconds: boolean});
* ```
* @param options
* @param [options.documentParams] - Whether to document the parameters of the functions
*/
getTypeScriptFunctionSignatures({ documentParams = true } = {}) {
const chatModelFunctions = this.chatModelFunctions;
if (!this.hasAnyFunctions || chatModelFunctions == null)
return "";
const functionNames = Object.keys(chatModelFunctions);
return functionNames
.map((functionName) => {
const functionDefinition = chatModelFunctions[functionName];
let res = "";
if (functionDefinition?.description != null && functionDefinition.description.trim() !== "")
res += "// " + functionDefinition.description.split("\n").join("\n// ") + "\n";
res += "function " + functionName + "(";
if (documentParams && functionDefinition?.params != null)
res += "params: " + getTypeScriptTypeStringForGbnfJsonSchema(functionDefinition.params);
else if (!documentParams && functionDefinition?.params != null)
res += "params";
res += ");";
return res;
})
.join("\n\n");
}
/**
* Example:
* ```ts
* // Retrieve the current date
* type getDate = () => any;
*
* // Retrieve the current time
* type getTime = (_: {hours: "24" | "12", seconds: boolean}) => any;
* ```
* @param options
* @param [options.documentParams] - Whether to document the parameters of the functions
* @param [options.reservedFunctionNames] - Function names that are reserved and cannot be used
*/
getTypeScriptFunctionTypes({ documentParams = true, reservedFunctionNames = [] } = {}) {
const chatModelFunctions = this.chatModelFunctions;
if (!this.hasAnyFunctions || chatModelFunctions == null)
return "";
const functionNames = Object.keys(chatModelFunctions);
const reservedFunctionNamesSet = new Set(reservedFunctionNames);
return functionNames
.map((functionName) => {
if (reservedFunctionNamesSet.has(functionName))
throw new Error(`Function name "${functionName}" is reserved and cannot be used`);
const functionDefinition = chatModelFunctions[functionName];
let res = "";
if (functionDefinition?.description != null && functionDefinition.description.trim() !== "")
res += "// " + functionDefinition.description.split("\n").join("\n// ") + "\n";
res += "type " + functionName + " = (";
if (documentParams && functionDefinition?.params != null)
res += "_: " + getTypeScriptTypeStringForGbnfJsonSchema(functionDefinition.params);
res += ") => any;";
return res;
})
.join("\n\n");
}
/* eslint-disable @stylistic/max-len */
/**
* Example:
* ```
* Use the function 'getDate' to: Retrieve the current date
* {"name": "getDate", "description": "Retrieve the current date"}
*
* Use the function 'getTime' to: Retrieve the current time
* {"name": "getTime", "description": "Retrieve the current time", "parameters": {"type": "object", "properties": {"hours": {"enum": ["24", "12"]}, "seconds": {"type": "boolean"}}}}
* ```
* @param options
* @param [options.documentParams] - Whether to document the parameters of the functions
*/
getLlama3_1FunctionSignatures({ documentParams = true } = {}) {
const chatModelFunctions = this.chatModelFunctions;
if (!this.hasAnyFunctions || chatModelFunctions == null)
return "";
const functionNames = Object.keys(chatModelFunctions);
return functionNames
.map((functionName) => {
const functionDefinition = chatModelFunctions[functionName];
let res = `Use the function '${functionName}'`;
const addDescription = functionDefinition?.description != null && functionDefinition.description.trim() !== "";
if (addDescription)
res += " to: " + functionDefinition.description.split("\n").join("\n// ") + "\n";
else
res += ".\n";
res += jsonDumps({
name: functionName,
...(addDescription ? { description: functionDefinition.description } : {}),
...(documentParams && functionDefinition?.params != null ? { parameters: functionDefinition.params } : {})
});
return res;
})
.join("\n\n");
}
/* eslint-enable @stylistic/max-len */
/* eslint-disable @stylistic/max-len */
/**
* Example:
* ```
* {"name": "getDate", "description": "Retrieve the current date"}
*
* {"name": "getTime", "description": "Retrieve the current time", "parameters": {"type": "object", "properties": {"hours": {"enum": ["24", "12"]}, "seconds": {"type": "boolean"}}}}
* ```
* @param options
* @param [options.documentParams] - Whether to document the parameters of the functions
*/
getLlama3_2LightweightFunctionSignatures({ documentParams = true } = {}) {
const chatModelFunctions = this.chatModelFunctions;
if (!this.hasAnyFunctions || chatModelFunctions == null)
return "";
const functionNames = Object.keys(chatModelFunctions);
const functionsLines = functionNames
.map((functionName) => {
const functionDefinition = chatModelFunctions[functionName];
const addDescription = functionDefinition?.description != null && functionDefinition.description.trim() !== "";
return jsonDumps({
name: functionName,
...(addDescription ? { description: functionDefinition.description } : {}),
...(documentParams && functionDefinition?.params != null ? { parameters: functionDefinition.params } : {})
});
})
.join("\n\n");
return functionsLines;
}
/* eslint-enable @stylistic/max-len */
getQwenFunctionSignatures({ documentParams = true } = {}) {
return this._convertToJinjaTools({ documentParams })
.map((tool) => jsonDumps(tool))
.join("\n");
}
/** @internal */
_convertToJinjaTools({ documentParams = true } = {}) {
const chatModelFunctions = this.chatModelFunctions;
if (!this.hasAnyFunctions || chatModelFunctions == null)
return [];
return [...Object.entries(chatModelFunctions)]
.map(([functionName, functionDefinition]) => {
return {
type: "function",
function: {
name: functionName,
description: functionDefinition.description,
parameters: documentParams
? functionDefinition.params
: undefined
}
};
});
}
}
//# sourceMappingURL=ChatModelFunctionsDocumentationGenerator.js.map