Skip to content

Commit 49acdcb

Browse files
committed
add support to format input json as typescript function str
1 parent 2e33911 commit 49acdcb

File tree

1 file changed

+101
-3
lines changed

1 file changed

+101
-3
lines changed

examples/server/utils.hpp

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ static json probs_vector_to_json(const llama_context * ctx, const std::vector<co
339339
//
340340

341341

342-
static std::string rubra_format_function_call_str(const std::vector<json> & functions, json & tool_name_map) {
342+
static std::string rubra_format_python_function_call_str(const std::vector<json> & functions, json & tool_name_map) {
343343
std::string final_str = "You have access to the following tools:\n";
344344
printf("rubra_format_function_call_str parsing...\n");
345345
json type_mapping = {
@@ -432,6 +432,104 @@ static std::string rubra_format_function_call_str(const std::vector<json> & func
432432
return final_str;
433433
}
434434

435+
436+
// Helper function to join strings with a delimiter
437+
static std::string helper_join(const std::vector<std::string>& elements, const std::string& delimiter) {
438+
std::string result;
439+
for (auto it = elements.begin(); it != elements.end(); ++it) {
440+
if (!result.empty()) {
441+
result += delimiter;
442+
}
443+
result += *it;
444+
}
445+
return result;
446+
}
447+
448+
static std::string rubra_format_typescript_function_call_str(const std::vector<json> &functions, json &tool_name_map) {
449+
std::string final_str = "You have access to the following tools:\n";
450+
json type_mapping = {
451+
{"string", "string"},
452+
{"integer", "number"},
453+
{"number", "number"},
454+
{"float", "number"},
455+
{"object", "any"},
456+
{"array", "any[]"},
457+
{"boolean", "boolean"},
458+
{"null", "null"}
459+
};
460+
461+
std::vector<std::string> function_definitions;
462+
for (const auto &function : functions) {
463+
const auto &spec = function.contains("function") ? function["function"] : function;
464+
std::string func_name = spec.value("name", "");
465+
if (func_name.find('-') != std::string::npos) {
466+
const std::string origin_func_name = func_name;
467+
std::replace(func_name.begin(), func_name.end(), '-', '_'); // replace "-" with "_" because - is invalid in typescript func name
468+
tool_name_map[func_name] = origin_func_name;
469+
}
470+
471+
const std::string description = spec.contains("description") ? spec["description"].get<std::string>() : "";
472+
const auto& parameters = spec.contains("parameters") ? spec["parameters"].value("properties", json({})) : json({});
473+
const auto& required_params = spec.contains("parameters") ? spec["parameters"].value("required", std::vector<std::string>()) : std::vector<std::string>();
474+
475+
std::vector<std::string> func_args;
476+
std::string docstring = "/**\n * " + description + "\n";
477+
478+
for (auto it = parameters.begin(); it != parameters.end(); ++it) {
479+
const std::string param = it.key();
480+
const json& details = it.value();
481+
std::string json_type = details["type"].get<std::string>();
482+
std::string ts_type = type_mapping.value(json_type, "any");
483+
std::string param_description = "";
484+
if (details.count("description") > 0) {
485+
param_description = details["description"]; // Assuming the description is the first element
486+
}
487+
if (details.count("enum") > 0) {
488+
std::string enum_values;
489+
for (const std::string val : details["enum"]) {
490+
if (!enum_values.empty()) {
491+
enum_values += " or ";
492+
}
493+
enum_values = enum_values+ "\"" + val + "\"";
494+
}
495+
if (details["enum"].size() == 1) {
496+
param_description += " Only Acceptable value is: " + enum_values;
497+
} else {
498+
param_description += " Only Acceptable values are: " + enum_values;
499+
}
500+
}
501+
if (param_description.empty()) {
502+
param_description = "No description provided.";
503+
}
504+
if (details.contains("enum")) {
505+
ts_type = "string"; // Enum is treated as string in typescript
506+
}
507+
std::string arg_str = param + ": " + ts_type;
508+
if (find(required_params.begin(), required_params.end(), param) == required_params.end()) {
509+
arg_str = param + "?: " + ts_type;
510+
docstring += " * @param " + param + " - " + param_description + "\n";
511+
} else {
512+
docstring += " * @param " + param + " - " + param_description + "\n";
513+
}
514+
func_args.push_back(arg_str);
515+
}
516+
docstring += " */\n";
517+
518+
std::string func_args_str = helper_join(func_args, ", ");
519+
std::string function_definition = docstring + "function " + func_name + "(" + func_args_str + "): any {}";
520+
521+
function_definitions.push_back(function_definition);
522+
}
523+
524+
for (const auto& def : function_definitions) {
525+
final_str += def + "\n\n";
526+
}
527+
final_str += "Use the following format if using tools:\n<<functions>>[toolname1(arg1=value1, arg2=value2, ...), toolname2(arg1=value1, arg2=value2, ...)]";
528+
return final_str;
529+
}
530+
531+
532+
435533
static std::string default_tool_formatter(const std::vector<json>& tools) {
436534
std::string toolText = "";
437535
std::vector<std::string> toolNames;
@@ -493,12 +591,12 @@ static json oaicompat_completion_params_parse(
493591

494592
if (body.contains("tools") && !body["tools"].empty()) {
495593
// function_str = default_tool_formatter(body["tool"]);
496-
function_str = rubra_format_function_call_str(body["tools"], tool_name_map);
594+
function_str = rubra_format_typescript_function_call_str(body["tools"], tool_name_map);
497595
}
498596
// If 'tool' is not set or empty, check 'functions'
499597
else if (body.contains("functions") && !body["functions"].empty()) {
500598
// function_str = default_tool_formatter(body["functions"]);
501-
function_str = rubra_format_function_call_str(body["functions"], tool_name_map);
599+
function_str = rubra_format_typescript_function_call_str(body["functions"], tool_name_map);
502600
}
503601
printf("\n=============Formatting Input from OPENAI format...============\n");
504602
if (function_str != "") {

0 commit comments

Comments
 (0)