(llmresult string, functionConfig FunctionsConfig)
| 929 | } |
| 930 | |
| 931 | func ParseFunctionCall(llmresult string, functionConfig FunctionsConfig) []FuncCallResults { |
| 932 | |
| 933 | xlog.Debug("LLM result", "len", len(llmresult), "head", truncForLog(llmresult)) |
| 934 | |
| 935 | for _, item := range functionConfig.ReplaceFunctionResults { |
| 936 | k, v := item.Key, item.Value |
| 937 | xlog.Debug("Replacing", "key", k, "value", v) |
| 938 | re := regexp.MustCompile(k) |
| 939 | llmresult = re.ReplaceAllString(llmresult, v) |
| 940 | } |
| 941 | xlog.Debug("LLM result(function cleanup)", "len", len(llmresult), "head", truncForLog(llmresult)) |
| 942 | |
| 943 | functionNameKey := defaultFunctionNameKey |
| 944 | functionArgumentsKey := defaultFunctionArgumentsKey |
| 945 | if functionConfig.FunctionNameKey != "" { |
| 946 | functionNameKey = functionConfig.FunctionNameKey |
| 947 | } |
| 948 | if functionConfig.FunctionArgumentsKey != "" { |
| 949 | functionArgumentsKey = functionConfig.FunctionArgumentsKey |
| 950 | } |
| 951 | |
| 952 | results := []FuncCallResults{} |
| 953 | llmResults := []string{} |
| 954 | |
| 955 | extractJSON := func(results []string) (result []FuncCallResults, e error) { |
| 956 | // As we have to change the result before processing, we can't stream the answer token-by-token (yet?) |
| 957 | result = make([]FuncCallResults, 0) |
| 958 | |
| 959 | for _, s := range results { |
| 960 | var ss []map[string]any |
| 961 | |
| 962 | s = utils.EscapeNewLines(s) |
| 963 | ss, err := ParseJSON(s) |
| 964 | //err := json.Unmarshal([]byte(s), &ss) |
| 965 | if err != nil { |
| 966 | xlog.Debug("unable to unmarshal llm result in a single object or an array of JSON objects", "error", err, "escapedLLMResult", s) |
| 967 | } |
| 968 | |
| 969 | xlog.Debug("Function return", "result", s, "parsed", ss) |
| 970 | |
| 971 | for _, s := range ss { |
| 972 | // The grammar defines the function name as "function", while OpenAI returns "name" |
| 973 | func_name, ok := s[functionNameKey] |
| 974 | if !ok { |
| 975 | continue |
| 976 | //return result, fmt.Errorf("unable to find function name in result") |
| 977 | } |
| 978 | // Arguments from grammar result is a map[string]interface{}, but OpenAI expects a stringified JSON object |
| 979 | // We marshal it to JSON string here to match OpenAI's format |
| 980 | args, ok := s[functionArgumentsKey] |
| 981 | if !ok { |
| 982 | continue |
| 983 | //return result, fmt.Errorf("unable to find arguments in result") |
| 984 | } |
| 985 | // Marshal arguments to JSON string (handles both object and string cases) |
| 986 | var d []byte |
| 987 | if argsStr, ok := args.(string); ok { |
| 988 | // Check if the string is valid JSON; if not, auto-heal if enabled |
no test coverage detected