From 935720ea908f81864807db6d37fa03ce723818ab Mon Sep 17 00:00:00 2001 From: cobular <22972550+Cobular@users.noreply.github.com> Date: Mon, 23 Oct 2023 13:00:20 -0700 Subject: [PATCH 1/2] Fixed issue with 3.5 Models halucinating a funciton called "python". I've found open-interpreter to be consistently running into the issue described here: https://community.openai.com/t/function-calling-a-python-function-is-frequently-called-even-though-it-does-not-exist-in-the-functions-parameter/264481/1, where 3.5 turbo frequently halucinates a fake funciton, and there's not much to do about that. I've added the ability to just process that function, if it's called. --- interpreter/llm/setup_openai_coding_llm.py | 67 ++++++++++++++++------ 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/interpreter/llm/setup_openai_coding_llm.py b/interpreter/llm/setup_openai_coding_llm.py index 763dc4f181..1ce8504606 100644 --- a/interpreter/llm/setup_openai_coding_llm.py +++ b/interpreter/llm/setup_openai_coding_llm.py @@ -99,6 +99,9 @@ def coding_llm(messages): for chunk in response: + if interpreter.debug_mode: + print("Chunk from LLM", chunk) + if ('choices' not in chunk or len(chunk['choices']) == 0): # This happens sometimes continue @@ -108,31 +111,61 @@ def coding_llm(messages): # Accumulate deltas accumulated_deltas = merge_deltas(accumulated_deltas, delta) + if interpreter.debug_mode: + print("Accumulated deltas", accumulated_deltas) + if "content" in delta and delta["content"]: yield {"message": delta["content"]} if ("function_call" in accumulated_deltas and "arguments" in accumulated_deltas["function_call"]): - arguments = accumulated_deltas["function_call"]["arguments"] - arguments = parse_partial_json(arguments) - - if arguments: - - if (language is None - and "language" in arguments - and "code" in arguments # <- This ensures we're *finished* typing language, as opposed to partially done - and arguments["language"]): - language = arguments["language"] + if ("name" in accumulated_deltas["function_call"] and accumulated_deltas["function_call"]["name"] == "execute"): + arguments = accumulated_deltas["function_call"]["arguments"] + arguments = parse_partial_json(arguments) + + if arguments: + if ("name" in arguments and arguments["name"] == "execute"): + if (language is None + and "language" in arguments + and "code" in arguments # <- This ensures we're *finished* typing language, as opposed to partially done + and arguments["language"]): + language = arguments["language"] + yield {"language": language} + + if language is not None and "code" in arguments: + # Calculate the delta (new characters only) + code_delta = arguments["code"][len(code):] + # Update the code + code = arguments["code"] + # Yield the delta + if code_delta: + yield {"code": code_delta} + else: + if interpreter.debug_mode: + print("Arguments not a dict.") + + # 3.5 REALLY likes to halucinate a function named `python` and you can't really fix that, it seems. + # We just need to deal with it. + elif ("name" in accumulated_deltas["function_call"] and accumulated_deltas["function_call"]["name"] == "python"): + if interpreter.debug_mode: + print("Got direct python call") + if (language is None): + language = "python" yield {"language": language} - - if language is not None and "code" in arguments: - # Calculate the delta (new characters only) - code_delta = arguments["code"][len(code):] + + if language is not None: + # Pull the code string straight out of the "arguments" string + code_delta = accumulated_deltas["function_call"]["arguments"][len(code):] # Update the code - code = arguments["code"] + code = accumulated_deltas["function_call"]["arguments"] # Yield the delta if code_delta: - yield {"code": code_delta} - + yield {"code": code_delta} + + else: + if interpreter.debug_mode: + print("GOT BAD FUNCTION CALL: ", accumulated_deltas["function_call"]) + + return coding_llm \ No newline at end of file From ef9cf62ddd3fea7f6d60c70accfa2b396568598d Mon Sep 17 00:00:00 2001 From: cobular <22972550+Cobular@users.noreply.github.com> Date: Mon, 23 Oct 2023 13:37:02 -0700 Subject: [PATCH 2/2] Don't break the default case --- interpreter/llm/setup_openai_coding_llm.py | 31 +++++++++++----------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/interpreter/llm/setup_openai_coding_llm.py b/interpreter/llm/setup_openai_coding_llm.py index 1ce8504606..da38068634 100644 --- a/interpreter/llm/setup_openai_coding_llm.py +++ b/interpreter/llm/setup_openai_coding_llm.py @@ -125,22 +125,21 @@ def coding_llm(messages): arguments = parse_partial_json(arguments) if arguments: - if ("name" in arguments and arguments["name"] == "execute"): - if (language is None - and "language" in arguments - and "code" in arguments # <- This ensures we're *finished* typing language, as opposed to partially done - and arguments["language"]): - language = arguments["language"] - yield {"language": language} - - if language is not None and "code" in arguments: - # Calculate the delta (new characters only) - code_delta = arguments["code"][len(code):] - # Update the code - code = arguments["code"] - # Yield the delta - if code_delta: - yield {"code": code_delta} + if (language is None + and "language" in arguments + and "code" in arguments # <- This ensures we're *finished* typing language, as opposed to partially done + and arguments["language"]): + language = arguments["language"] + yield {"language": language} + + if language is not None and "code" in arguments: + # Calculate the delta (new characters only) + code_delta = arguments["code"][len(code):] + # Update the code + code = arguments["code"] + # Yield the delta + if code_delta: + yield {"code": code_delta} else: if interpreter.debug_mode: print("Arguments not a dict.")