diff options
-rw-r--r-- | continuedev/src/continuedev/core/autopilot.py | 10 | ||||
-rw-r--r-- | continuedev/src/continuedev/libs/util/calculate_diff.py | 14 | ||||
-rw-r--r-- | continuedev/src/continuedev/server/gui.py | 10 | ||||
-rw-r--r-- | continuedev/src/continuedev/server/gui_protocol.py | 8 | ||||
-rw-r--r-- | continuedev/src/continuedev/steps/core/core.py | 2 | ||||
-rw-r--r-- | extension/react-app/src/components/StepContainer.tsx | 44 | ||||
-rw-r--r-- | extension/react-app/src/components/index.ts | 18 | ||||
-rw-r--r-- | extension/react-app/src/hooks/ContinueGUIClientProtocol.ts | 6 | ||||
-rw-r--r-- | extension/react-app/src/hooks/useContinueGUIProtocol.ts | 8 | ||||
-rw-r--r-- | extension/react-app/src/tabs/gui.tsx | 272 |
10 files changed, 245 insertions, 147 deletions
diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py index c979d53a..1642003c 100644 --- a/continuedev/src/continuedev/core/autopilot.py +++ b/continuedev/src/continuedev/core/autopilot.py @@ -40,6 +40,12 @@ class Autopilot(ContinueBaseModel): def get_full_state(self) -> FullState: return FullState(history=self.history, active=self._active, user_input_queue=self._main_user_input_queue) + async def clear_history(self): + self.history = History.from_empty() + self._main_user_input_queue = [] + self._active = False + await self.update_subscribers() + def on_update(self, callback: Coroutine["FullState", None, None]): """Subscribe to changes to state""" self._on_update_callbacks.append(callback) @@ -88,6 +94,10 @@ class Autopilot(ContinueBaseModel): async def retry_at_index(self, index: int): self._retry_queue.post(str(index), None) + async def delete_at_index(self, index: int): + self.history.timeline[index].step.hide = True + await self.update_subscribers() + async def _run_singular_step(self, step: "Step", is_future_step: bool = False) -> Coroutine[Observation, None, None]: capture_event( 'step run', {'step_name': step.name, 'params': step.dict()}) diff --git a/continuedev/src/continuedev/libs/util/calculate_diff.py b/continuedev/src/continuedev/libs/util/calculate_diff.py index d778891b..ff0a135f 100644 --- a/continuedev/src/continuedev/libs/util/calculate_diff.py +++ b/continuedev/src/continuedev/libs/util/calculate_diff.py @@ -67,6 +67,20 @@ def calculate_diff(filepath: str, original: str, updated: str) -> List[FileEdit] def calculate_diff2(filepath: str, original: str, updated: str) -> List[FileEdit]: + # original_lines = original.splitlines() + # updated_lines = updated.splitlines() + # offset = 0 + # while len(original_lines) and len(updated_lines) and original_lines[0] == updated_lines[0]: + # original_lines = original_lines[1:] + # updated_lines = updated_lines[1:] + + # while len(original_lines) and len(updated_lines) and original_lines[-1] == updated_lines[-1]: + # original_lines = original_lines[:-1] + # updated_lines = updated_lines[:-1] + + # original = "\n".join(original_lines) + # updated = "\n".join(updated_lines) + edits = [] max_iterations = 1000 i = 0 diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py index b873a88f..e8b52004 100644 --- a/continuedev/src/continuedev/server/gui.py +++ b/continuedev/src/continuedev/server/gui.py @@ -77,6 +77,10 @@ class GUIProtocolServer(AbstractGUIProtocolServer): self.on_reverse_to_index(data["index"]) elif message_type == "retry_at_index": self.on_retry_at_index(data["index"]) + elif message_type == "clear_history": + self.on_clear_history() + elif message_type == "delete_at_index": + self.on_delete_at_index(data["index"]) except Exception as e: print(e) @@ -106,6 +110,12 @@ class GUIProtocolServer(AbstractGUIProtocolServer): asyncio.create_task( self.session.autopilot.retry_at_index(index)) + def on_clear_history(self): + asyncio.create_task(self.session.autopilot.clear_history()) + + def on_delete_at_index(self, index: int): + asyncio.create_task(self.session.autopilot.delete_at_index(index)) + @router.websocket("/ws") async def websocket_endpoint(websocket: WebSocket, session: Session = Depends(websocket_session)): diff --git a/continuedev/src/continuedev/server/gui_protocol.py b/continuedev/src/continuedev/server/gui_protocol.py index 287f9e3b..889c6761 100644 --- a/continuedev/src/continuedev/server/gui_protocol.py +++ b/continuedev/src/continuedev/server/gui_protocol.py @@ -30,3 +30,11 @@ class AbstractGUIProtocolServer(ABC): @abstractmethod def on_retry_at_index(self, index: int): """Called when the user requests a retry at a previous index""" + + @abstractmethod + def on_clear_history(self): + """Called when the user requests to clear the history""" + + @abstractmethod + def on_delete_at_index(self, index: int): + """Called when the user requests to delete a step at a given index""" diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index 4288ffd2..dacf0e7b 100644 --- a/continuedev/src/continuedev/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -193,7 +193,7 @@ class Gpt35EditCodeStep(Step): edit.range.end.line += rif.range.start.line edit.range.end.character += rif.range.start.character if edit.range.end.line == 0 else 0 - for line in range(edit.range.start.line, edit.range.end.line + 1): + for line in range(edit.range.start.line, edit.range.end.line + 1 + len(edit.replacement.splitlines()) - (edit.range.end.line - edit.range.start.line + 1)): lines_to_highlight.add(line) await sdk.ide.applyFileSystemEdit(edit) diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx index fb0143b5..2d85b4f0 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -7,6 +7,7 @@ import { vscBackground, GradientBorder, vscBackgroundTransparent, + HeaderButton, } from "."; import { RangeInFile, FileEdit } from "../../../src/client"; import CodeBlock from "./CodeBlock"; @@ -15,7 +16,7 @@ import SubContainer from "./SubContainer"; import { ChevronDown, ChevronRight, - Backward, + XMark, ArrowPath, } from "@styled-icons/heroicons-outline"; import { HistoryNode } from "../../../schema/HistoryNode"; @@ -31,6 +32,7 @@ interface StepContainerProps { onRefinement: (input: string) => void; onUserInput: (input: string) => void; onRetry: () => void; + onDelete: () => void; open?: boolean; } @@ -54,8 +56,10 @@ const HeaderDiv = styled.div<{ error: boolean }>` background-color: ${(props) => props.error ? "#522" : vscBackgroundTransparent}; display: grid; - grid-template-columns: 1fr auto; + grid-template-columns: 1fr auto auto; + grid-gap: 8px; align-items: center; + padding-right: 8px; `; const ContentDiv = styled.div` @@ -64,20 +68,6 @@ const ContentDiv = styled.div` background-color: ${vscBackground}; `; -const HeaderButton = styled.button` - background-color: transparent; - border: 1px solid white; - border-radius: ${defaultBorderRadius}; - padding: 2px; - cursor: pointer; - color: white; - - &:hover { - background-color: white; - color: black; - } -`; - const OnHoverDiv = styled.div` text-align: center; padding: 10px; @@ -161,18 +151,28 @@ function StepContainer(props: StepContainerProps) { <Backward size="1.6em" onClick={props.onReverse}></Backward> </HeaderButton> */} - {props.historyNode.observation?.error ? ( + <> <HeaderButton onClick={(e) => { e.stopPropagation(); - props.onRetry(); + props.onDelete(); }} > - <ArrowPath size="1.6em" onClick={props.onRetry}></ArrowPath> + <XMark size="1.6em" onClick={props.onDelete} /> </HeaderButton> - ) : ( - <></> - )} + {props.historyNode.observation?.error ? ( + <HeaderButton + onClick={(e) => { + e.stopPropagation(); + props.onRetry(); + }} + > + <ArrowPath size="1.6em" onClick={props.onRetry} /> + </HeaderButton> + ) : ( + <></> + )} + </> </HeaderDiv> </GradientBorder> <ContentDiv hidden={!open}> diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts index 4966f3e8..525989af 100644 --- a/extension/react-app/src/components/index.ts +++ b/extension/react-app/src/components/index.ts @@ -143,3 +143,21 @@ export const appear = keyframes` transform: translateY(0px); } `; + +export const HeaderButton = styled.button` + background-color: transparent; + border: 1px solid white; + border-radius: ${defaultBorderRadius}; + cursor: pointer; + color: white; + + &:hover { + background-color: white; + color: black; + } + display: flex; + align-items: center; + justify-content: center; + gap: 4px; + padding: 1px; +`; diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts index 18a91de7..71303c70 100644 --- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts +++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts @@ -8,6 +8,12 @@ abstract class AbstractContinueGUIClientProtocol { abstract sendStepUserInput(input: string, index: number): void; abstract onStateUpdate(state: any): void; + + abstract sendClear(): void; + + abstract retryAtIndex(index: number): void; + + abstract deleteAtIndex(index: number): void; } export default AbstractContinueGUIClientProtocol; diff --git a/extension/react-app/src/hooks/useContinueGUIProtocol.ts b/extension/react-app/src/hooks/useContinueGUIProtocol.ts index f27895fb..a8e28fc5 100644 --- a/extension/react-app/src/hooks/useContinueGUIProtocol.ts +++ b/extension/react-app/src/hooks/useContinueGUIProtocol.ts @@ -45,9 +45,17 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol { }); } + sendClear() { + this.messenger.send("clear_history", {}); + } + retryAtIndex(index: number) { this.messenger.send("retry_at_index", { index }); } + + deleteAtIndex(index: number) { + this.messenger.send("delete_at_index", { index }); + } } export default ContinueGUIClientProtocol; diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index 9f7e651f..cb7a5440 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -4,6 +4,7 @@ import { vscBackground, Loader, MainTextInput, + HeaderButton, } from "../components"; import ContinueButton from "../components/ContinueButton"; import { useCallback, useEffect, useRef, useState } from "react"; @@ -11,7 +12,7 @@ import { History } from "../../../schema/History"; import { HistoryNode } from "../../../schema/HistoryNode"; import StepContainer from "../components/StepContainer"; import useContinueGUIProtocol from "../hooks/useWebsocket"; - +import { Trash } from "@styled-icons/heroicons-outline"; let TopGUIDiv = styled.div` display: grid; grid-template-columns: 1fr; @@ -26,6 +27,14 @@ let UserInputQueueItem = styled.div` text-align: center; `; +const TopBar = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 8px; + align-items: center; +`; + interface GUIProps { firstObservation?: any; } @@ -33,129 +42,128 @@ interface GUIProps { function GUI(props: GUIProps) { const [waitingForSteps, setWaitingForSteps] = useState(false); const [userInputQueue, setUserInputQueue] = useState<string[]>([]); - const [history, setHistory] = useState<History | undefined>(); - // { - // timeline: [ - // { - // step: { - // name: "Waiting for user input", - // cmd: "python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py", - // description: - // "Run `python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py` and ```\nprint(sum(first, second))\n```\n- Testing\n- Testing 2\n- Testing 3", - // }, - // observation: { - // title: "ERROR FOUND", - // error: - // "Traceback (most recent call last):\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/main.py\", line 7, in <module>\n print(sum(first, second))\n ^^^^^^^^^^^^^^^^^^\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/sum.py\", line 2, in sum\n return a + b\n ~~^~~\nTypeError: unsupported operand type(s) for +: 'int' and 'str'", - // }, - // output: [ - // { - // traceback: { - // frames: [ - // { - // filepath: - // "/Users/natesesti/Desktop/continue/extension/examples/python/main.py", - // lineno: 7, - // function: "<module>", - // code: "print(sum(first, second))", - // }, - // ], - // message: "unsupported operand type(s) for +: 'int' and 'str'", - // error_type: - // ' ^^^^^^^^^^^^^^^^^^\n File "/Users/natesesti/Desktop/continue/extension/examples/python/sum.py", line 2, in sum\n return a + b\n ~~^~~\nTypeError', - // full_traceback: - // "Traceback (most recent call last):\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/main.py\", line 7, in <module>\n print(sum(first, second))\n ^^^^^^^^^^^^^^^^^^\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/sum.py\", line 2, in sum\n return a + b\n ~~^~~\nTypeError: unsupported operand type(s) for +: 'int' and 'str'", - // }, - // }, - // null, - // ], - // }, - // { - // step: { - // name: "EditCodeStep", - // range_in_files: [ - // { - // filepath: - // "/Users/natesesti/Desktop/continue/extension/examples/python/main.py", - // range: { - // start: { - // line: 0, - // character: 0, - // }, - // end: { - // line: 6, - // character: 25, - // }, - // }, - // }, - // ], - // prompt: - // "I ran into this problem with my Python code:\n\n Traceback (most recent call last):\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/main.py\", line 7, in <module>\n print(sum(first, second))\n ^^^^^^^^^^^^^^^^^^\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/sum.py\", line 2, in sum\n return a + b\n ~~^~~\nTypeError: unsupported operand type(s) for +: 'int' and 'str'\n\n Below are the files that might need to be fixed:\n\n {code}\n\n This is what the code should be in order to avoid the problem:\n", - // description: - // "Run `python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py` and\n```python\nprint(sum(first, second))\n```\n- Testing\n- Testing 2\n- Testing 3", - // }, - // output: [ - // null, - // { - // reversible: true, - // actions: [ - // { - // reversible: true, - // filesystem: {}, - // filepath: - // "/Users/natesesti/Desktop/continue/extension/examples/python/main.py", - // range: { - // start: { - // line: 0, - // character: 0, - // }, - // end: { - // line: 6, - // character: 25, - // }, - // }, - // replacement: - // "\nfrom sum import sum\n\nfirst = 1\nsecond = 2\n\nprint(sum(first, second))", - // }, - // ], - // }, - // ], - // }, - // { - // step: { - // name: "SolveTracebackStep", - // traceback: { - // frames: [ - // { - // filepath: - // "/Users/natesesti/Desktop/continue/extension/examples/python/main.py", - // lineno: 7, - // function: "<module>", - // code: "print(sum(first, second))", - // }, - // ], - // message: "unsupported operand type(s) for +: 'int' and 'str'", - // error_type: - // ' ^^^^^^^^^^^^^^^^^^\n File "/Users/natesesti/Desktop/continue/extension/examples/python/sum.py", line 2, in sum\n return a + b\n ~~^~~\nTypeError', - // full_traceback: - // "Traceback (most recent call last):\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/main.py\", line 7, in <module>\n print(sum(first, second))\n ^^^^^^^^^^^^^^^^^^\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/sum.py\", line 2, in sum\n return a + b\n ~~^~~\nTypeError: unsupported operand type(s) for +: 'int' and 'str'", - // }, - // description: "Running step: SolveTracebackStep", - // }, - // output: [null, null], - // }, - // { - // step: { - // name: "RunCodeStep", - // cmd: "python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py", - // description: - // "Run `python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py`", - // }, - // output: [null, null], - // }, - // ], - // current_index: 3, - // } as any); + const [history, setHistory] = useState<History | undefined>({ + timeline: [ + { + step: { + name: "Waiting for user input", + cmd: "python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py", + description: + "Run `python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py` and ```\nprint(sum(first, second))\n```\n- Testing\n- Testing 2\n- Testing 3", + }, + observation: { + title: "ERROR FOUND", + error: + "Traceback (most recent call last):\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/main.py\", line 7, in <module>\n print(sum(first, second))\n ^^^^^^^^^^^^^^^^^^\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/sum.py\", line 2, in sum\n return a + b\n ~~^~~\nTypeError: unsupported operand type(s) for +: 'int' and 'str'", + }, + output: [ + { + traceback: { + frames: [ + { + filepath: + "/Users/natesesti/Desktop/continue/extension/examples/python/main.py", + lineno: 7, + function: "<module>", + code: "print(sum(first, second))", + }, + ], + message: "unsupported operand type(s) for +: 'int' and 'str'", + error_type: + ' ^^^^^^^^^^^^^^^^^^\n File "/Users/natesesti/Desktop/continue/extension/examples/python/sum.py", line 2, in sum\n return a + b\n ~~^~~\nTypeError', + full_traceback: + "Traceback (most recent call last):\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/main.py\", line 7, in <module>\n print(sum(first, second))\n ^^^^^^^^^^^^^^^^^^\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/sum.py\", line 2, in sum\n return a + b\n ~~^~~\nTypeError: unsupported operand type(s) for +: 'int' and 'str'", + }, + }, + null, + ], + }, + { + step: { + name: "EditCodeStep", + range_in_files: [ + { + filepath: + "/Users/natesesti/Desktop/continue/extension/examples/python/main.py", + range: { + start: { + line: 0, + character: 0, + }, + end: { + line: 6, + character: 25, + }, + }, + }, + ], + prompt: + "I ran into this problem with my Python code:\n\n Traceback (most recent call last):\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/main.py\", line 7, in <module>\n print(sum(first, second))\n ^^^^^^^^^^^^^^^^^^\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/sum.py\", line 2, in sum\n return a + b\n ~~^~~\nTypeError: unsupported operand type(s) for +: 'int' and 'str'\n\n Below are the files that might need to be fixed:\n\n {code}\n\n This is what the code should be in order to avoid the problem:\n", + description: + "Run `python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py` and\n```python\nprint(sum(first, second))\n```\n- Testing\n- Testing 2\n- Testing 3", + }, + output: [ + null, + { + reversible: true, + actions: [ + { + reversible: true, + filesystem: {}, + filepath: + "/Users/natesesti/Desktop/continue/extension/examples/python/main.py", + range: { + start: { + line: 0, + character: 0, + }, + end: { + line: 6, + character: 25, + }, + }, + replacement: + "\nfrom sum import sum\n\nfirst = 1\nsecond = 2\n\nprint(sum(first, second))", + }, + ], + }, + ], + }, + { + step: { + name: "SolveTracebackStep", + traceback: { + frames: [ + { + filepath: + "/Users/natesesti/Desktop/continue/extension/examples/python/main.py", + lineno: 7, + function: "<module>", + code: "print(sum(first, second))", + }, + ], + message: "unsupported operand type(s) for +: 'int' and 'str'", + error_type: + ' ^^^^^^^^^^^^^^^^^^\n File "/Users/natesesti/Desktop/continue/extension/examples/python/sum.py", line 2, in sum\n return a + b\n ~~^~~\nTypeError', + full_traceback: + "Traceback (most recent call last):\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/main.py\", line 7, in <module>\n print(sum(first, second))\n ^^^^^^^^^^^^^^^^^^\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/sum.py\", line 2, in sum\n return a + b\n ~~^~~\nTypeError: unsupported operand type(s) for +: 'int' and 'str'", + }, + description: "Running step: SolveTracebackStep", + }, + output: [null, null], + }, + { + step: { + name: "RunCodeStep", + cmd: "python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py", + description: + "Run `python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py`", + }, + output: [null, null], + }, + ], + current_index: 3, + } as any); const topGuiDivRef = useRef<HTMLDivElement>(null); const client = useContinueGUIProtocol(); @@ -261,6 +269,19 @@ function GUI(props: GUIProps) { } }} > + <TopBar> + <h3>Continue</h3> + <HeaderButton style={{ padding: "3px" }}> + Clear History + <Trash + size="1.6em" + onClick={() => { + client?.sendClear(); + }} + /> + </HeaderButton> + </TopBar> + {typeof client === "undefined" && ( <> <Loader></Loader> @@ -288,6 +309,9 @@ function GUI(props: GUIProps) { client?.retryAtIndex(index); setWaitingForSteps(true); }} + onDelete={() => { + client?.deleteAtIndex(index); + }} /> ); })} |