From 1da66af471329204dec9749451d533a47212c7fa Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Thu, 29 Jun 2023 22:46:56 -0700
Subject: lock suggestions until done streaming

---
 continuedev/src/continuedev/server/ide.py          |  9 +++++++++
 continuedev/src/continuedev/server/ide_protocol.py |  4 ++++
 continuedev/src/continuedev/steps/chat.py          | 22 +++++++++++++---------
 continuedev/src/continuedev/steps/core/core.py     |  3 ++-
 4 files changed, 28 insertions(+), 10 deletions(-)

(limited to 'continuedev/src')

diff --git a/continuedev/src/continuedev/server/ide.py b/continuedev/src/continuedev/server/ide.py
index cc8cb15e..65f3ee74 100644
--- a/continuedev/src/continuedev/server/ide.py
+++ b/continuedev/src/continuedev/server/ide.py
@@ -132,6 +132,8 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
             await self.openGUI()
         elif message_type == "setFileOpen":
             await self.setFileOpen(data["filepath"], data["open"])
+        elif message_type == "setSuggestionsLocked":
+            await self.setSuggestionsLocked(data["filepath"], data["locked"])
         elif message_type == "fileEdits":
             fileEdits = list(
                 map(lambda d: FileEditWithFullContents.parse_obj(d), data["fileEdits"]))
@@ -158,6 +160,13 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
             "open": open
         })
 
+    async def setSuggestionsLocked(self, filepath: str, locked: bool = True):
+        # Lock suggestions in the file so they don't ruin the offset before others are inserted
+        await self._send_json("setSuggestionsLocked", {
+            "filepath": filepath,
+            "locked": locked
+        })
+
     async def openGUI(self):
         session_id = self.session_manager.new_session(self)
         await self._send_json("openGUI", {
diff --git a/continuedev/src/continuedev/server/ide_protocol.py b/continuedev/src/continuedev/server/ide_protocol.py
index 79820c36..d2dafa9a 100644
--- a/continuedev/src/continuedev/server/ide_protocol.py
+++ b/continuedev/src/continuedev/server/ide_protocol.py
@@ -23,6 +23,10 @@ class AbstractIdeProtocolServer(ABC):
     async def setFileOpen(self, filepath: str, open: bool = True):
         """Set whether a file is open"""
 
+    @abstractmethod
+    async def setSuggestionsLocked(self, filepath: str, locked: bool = True):
+        """Set whether suggestions are locked"""
+
     @abstractmethod
     async def openGUI(self):
         """Open a GUI"""
diff --git a/continuedev/src/continuedev/steps/chat.py b/continuedev/src/continuedev/steps/chat.py
index 5b4318c3..6a2c136e 100644
--- a/continuedev/src/continuedev/steps/chat.py
+++ b/continuedev/src/continuedev/steps/chat.py
@@ -152,8 +152,8 @@ class ChatWithFunctions(Step):
         ))
 
         last_function_called_index_in_history = None
-        # GPT keeps wanting to call the non-existent 'python' function repeatedly, so limiting to once
-        already_called_python = False
+        last_function_called_name = None
+        last_function_called_params = None
         while True:
             was_function_called = False
             func_args = ""
@@ -196,10 +196,8 @@ class ChatWithFunctions(Step):
                 ))
                 break
             else:
+                last_function_called = func_name
                 if func_name == "python" and "python" not in step_name_step_class_map:
-                    if already_called_python:
-                        return
-                    already_called_python = True
                     # GPT must be fine-tuned to believe this exists, but it doesn't always
                     func_name = "EditHighlightedCodeStep"
                     func_args = json.dumps({"user_input": self.user_input})
@@ -239,8 +237,6 @@ class ChatWithFunctions(Step):
                 if func_name not in step_name_step_class_map:
                     raise Exception(
                         f"The model tried to call a function ({func_name}) that does not exist. Please try again.")
-                step_to_run = step_name_step_class_map[func_name](
-                    **fn_call_params)
 
                 # if func_name == "AddFileStep":
                 #     step_to_run.hide = True
@@ -251,9 +247,17 @@ class ChatWithFunctions(Step):
                 # else:
                 #     self.description += f"\n`Running function {func_name}`\n\n"
                 if func_name == "EditHighlightedCodeStep":
-                    step_to_run.user_input = self.user_input
+                    fn_call_params["user_input"] = self.user_input
                 elif func_name == "EditFile":
-                    step_to_run.instructions = self.user_input
+                    fn_call_params["instructions"] = self.user_input
+
+                step_to_run = step_name_step_class_map[func_name](
+                    **fn_call_params)
+                if last_function_called_name is not None and last_function_called_name == func_name and last_function_called_params is not None and last_function_called_params == fn_call_params:
+                    # If it's calling the same function more than once in a row, it's probably looping and confused
+                    return
+                last_function_called_name = func_name
+                last_function_called_params = fn_call_params
 
                 await sdk.run_step(step_to_run)
                 await sdk.update_ui()
diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py
index e9420ea9..46c6a615 100644
--- a/continuedev/src/continuedev/steps/core/core.py
+++ b/continuedev/src/continuedev/steps/core/core.py
@@ -490,8 +490,9 @@ class DefaultModelEditCodeStep(Step):
 
         for rif in rif_with_contents:
             await sdk.ide.setFileOpen(rif.filepath)
+            await sdk.ide.setSuggestionsLocked(rif.filepath, True)
             await self.stream_rif(rif, sdk)
-            # await sdk.ide.saveFile(rif.filepath)
+            await sdk.ide.setSuggestionsLocked(rif.filepath, False)
 
 
 class EditFileStep(Step):
-- 
cgit v1.2.3-70-g09d2