summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--continuedev/src/continuedev/core/autopilot.py11
-rw-r--r--continuedev/src/continuedev/core/config.py6
-rw-r--r--continuedev/src/continuedev/core/main.py5
-rw-r--r--continuedev/src/continuedev/server/gui.py9
-rw-r--r--continuedev/src/continuedev/steps/chat.py4
-rw-r--r--continuedev/src/continuedev/steps/core/core.py4
-rw-r--r--extension/react-app/src/components/StepContainer.tsx31
-rw-r--r--extension/react-app/src/components/UserInputContainer.tsx57
-rw-r--r--extension/react-app/src/components/index.ts2
-rw-r--r--extension/react-app/src/tabs/gui.tsx33
10 files changed, 116 insertions, 46 deletions
diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index 1a77ca64..b3b98b8b 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -66,11 +66,16 @@ class Autopilot(ContinueBaseModel):
active=self._active,
user_input_queue=self._main_user_input_queue,
default_model=self.continue_sdk.config.default_model,
- highlighted_ranges=self._highlighted_ranges
+ highlighted_ranges=self._highlighted_ranges,
+ slash_commands=self.get_available_slash_commands()
)
- async def get_available_slash_commands(self) -> List[Dict]:
- return list(map(lambda x: {"name": x.name, "description": x.description}, self.continue_sdk.config.slash_commands)) or []
+ def get_available_slash_commands(self) -> List[Dict]:
+ custom_commands = list(map(lambda x: {
+ "name": x.name, "description": x.prompt}, self.continue_sdk.config.custom_commands)) or []
+ slash_commands = list(map(lambda x: {
+ "name": x.name, "description": x.description}, self.continue_sdk.config.slash_commands)) or []
+ return custom_commands + slash_commands
async def change_default_model(self, model: str):
self.continue_sdk.update_default_model(model)
diff --git a/continuedev/src/continuedev/core/config.py b/continuedev/src/continuedev/core/config.py
index ed5d785a..d268d247 100644
--- a/continuedev/src/continuedev/core/config.py
+++ b/continuedev/src/continuedev/core/config.py
@@ -12,6 +12,11 @@ class SlashCommand(BaseModel):
params: Optional[Dict] = {}
+class CustomCommand(BaseModel):
+ name: str
+ prompt: str
+
+
class OnTracebackSteps(BaseModel):
step_name: str
params: Optional[Dict] = {}
@@ -27,6 +32,7 @@ class ContinueConfig(BaseModel):
allow_anonymous_telemetry: Optional[bool] = True
default_model: Literal["gpt-3.5-turbo", "gpt-3.5-turbo-16k",
"gpt-4"] = 'gpt-4'
+ custom_commands: Optional[List[CustomCommand]] = []
slash_commands: Optional[List[SlashCommand]] = [
# SlashCommand(
# name="pytest",
diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py
index 7dff6f53..9a6617f4 100644
--- a/continuedev/src/continuedev/core/main.py
+++ b/continuedev/src/continuedev/core/main.py
@@ -196,6 +196,10 @@ class History(ContinueBaseModel):
return cls(timeline=[], current_index=-1)
+class SlashCommandDescription(ContinueBaseModel):
+ name: str
+ description: str
+
class FullState(ContinueBaseModel):
"""A full state of the program, including the history"""
history: History
@@ -203,6 +207,7 @@ class FullState(ContinueBaseModel):
user_input_queue: List[str]
default_model: str
highlighted_ranges: List[RangeInFileWithContents]
+ slash_commands: List[SlashCommandDescription]
class ContinueSDK:
diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py
index 9a33fb6c..b2f23bac 100644
--- a/continuedev/src/continuedev/server/gui.py
+++ b/continuedev/src/continuedev/server/gui.py
@@ -94,12 +94,6 @@ class GUIProtocolServer(AbstractGUIProtocolServer):
"state": state
})
- async def send_available_slash_commands(self):
- commands = await self.session.autopilot.get_available_slash_commands()
- await self._send_json("available_slash_commands", {
- "commands": commands
- })
-
def on_main_input(self, input: str):
# Do something with user input
asyncio.create_task(self.session.autopilot.accept_user_input(input))
@@ -147,8 +141,7 @@ async def websocket_endpoint(websocket: WebSocket, session: Session = Depends(we
protocol.websocket = websocket
# Update any history that may have happened before connection
- await protocol.send_available_slash_commands()
- # await protocol.send_state_update() THIS WAS CAUSING A LOT OF ISSUES. Don't uncomment.
+ await protocol.send_state_update()
while AppStatus.should_exit is False:
message = await websocket.receive_text()
diff --git a/continuedev/src/continuedev/steps/chat.py b/continuedev/src/continuedev/steps/chat.py
index 013cb578..49dd98e4 100644
--- a/continuedev/src/continuedev/steps/chat.py
+++ b/continuedev/src/continuedev/steps/chat.py
@@ -22,9 +22,9 @@ class SimpleChatStep(Step):
user_input: str
name: str = "Chat"
manage_own_chat_context: bool = True
+ description: str = ""
async def run(self, sdk: ContinueSDK):
- self.description = f"`{self.user_input}`\n\n"
if self.user_input.strip() == "":
self.user_input = "Explain this code's function is a concise list of markdown bullets."
self.description = ""
@@ -148,9 +148,9 @@ class ChatWithFunctions(Step):
DeleteFileStep(filename=""), RunTerminalCommandStep(command="")]
name: str = "Input"
manage_own_chat_context: bool = True
+ description: str = ""
async def run(self, sdk: ContinueSDK):
- self.description = f"```{self.user_input}```"
await sdk.update_ui()
step_name_step_class_map = {
diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py
index 4eb2445c..4ad47689 100644
--- a/continuedev/src/continuedev/steps/core/core.py
+++ b/continuedev/src/continuedev/steps/core/core.py
@@ -116,6 +116,7 @@ class DefaultModelEditCodeStep(Step):
range_in_files: List[RangeInFile]
name: str = "Editing Code"
hide = False
+ description: str = ""
_prompt: str = dedent("""\
Take the file prefix and suffix into account, but only rewrite the code_to_edit as specified in the user_request. The code you write in modified_code_to_edit will replace the code between the code_to_edit tags. Do NOT preface your answer or write anything other than code. The </modified_code_to_edit> tag should be written to indicate the end of the modified code section. Do not ever use nested tags.
@@ -508,7 +509,6 @@ class DefaultModelEditCodeStep(Step):
self._prompt_and_completion += prompt + completion
async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]:
- self.description = f"`{self.user_input}`"
await sdk.update_ui()
rif_with_contents = []
@@ -589,7 +589,7 @@ class ManualEditStep(ReversibleStep):
class UserInputStep(Step):
user_input: str
name: str = "User Input"
- hide: bool = True
+ hide: bool = False
manage_own_chat_context: bool = True
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index cb83f20a..ab0d307f 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -22,7 +22,6 @@ interface StepContainerProps {
historyNode: HistoryNode;
onReverse: () => void;
inFuture: boolean;
- onRefinement: (input: string) => void;
onUserInput: (input: string) => void;
onRetry: () => void;
onDelete: () => void;
@@ -33,6 +32,8 @@ interface StepContainerProps {
isLast: boolean;
}
+// #region styled components
+
const MainDiv = styled.div<{ stepDepth: number; inFuture: boolean }>`
opacity: ${(props) => (props.inFuture ? 0.3 : 1)};
animation: ${appear} 0.3s ease-in-out;
@@ -63,9 +64,12 @@ const HeaderDiv = styled.div<{ error: boolean; loading: boolean }>`
padding-right: 8px;
`;
-const ContentDiv = styled.div`
+const ContentDiv = styled.div<{ isUserInput: boolean }>`
padding: 8px;
padding-left: 16px;
+ background-color: ${(props) =>
+ props.isUserInput ? secondaryDark : vscBackground};
+ font-size: 13px;
`;
const MarkdownPre = styled.pre`
@@ -119,10 +123,13 @@ const GradientBorder = styled.div<{
background-size: 200% 200%;
`;
+// #endregion
+
function StepContainer(props: StepContainerProps) {
const [isHovered, setIsHovered] = useState(false);
const naturalLanguageInputRef = useRef<HTMLTextAreaElement>(null);
const userInputRef = useRef<HTMLInputElement>(null);
+ const isUserInput = props.historyNode.step.name === "UserInputStep";
useEffect(() => {
if (userInputRef?.current) {
@@ -136,13 +143,6 @@ function StepContainer(props: StepContainerProps) {
}
}, [isHovered]);
- const onTextInput = useCallback(() => {
- if (naturalLanguageInputRef.current) {
- props.onRefinement(naturalLanguageInputRef.current.value);
- naturalLanguageInputRef.current.value = "";
- }
- }, [naturalLanguageInputRef]);
-
return (
<MainDiv
stepDepth={(props.historyNode.depth as any) || 0}
@@ -181,11 +181,12 @@ function StepContainer(props: StepContainerProps) {
error={props.historyNode.observation?.error ? true : false}
>
<h4 className="m-2">
- {props.open ? (
- <ChevronDown size="1.4em" />
- ) : (
- <ChevronRight size="1.4em" />
- )}
+ {!isUserInput &&
+ (props.open ? (
+ <ChevronDown size="1.4em" />
+ ) : (
+ <ChevronRight size="1.4em" />
+ ))}
{props.historyNode.observation?.title ||
(props.historyNode.step.name as any)}
</h4>
@@ -225,7 +226,7 @@ function StepContainer(props: StepContainerProps) {
</>
</HeaderDiv>
</GradientBorder>
- <ContentDiv hidden={!props.open}>
+ <ContentDiv hidden={!props.open} isUserInput={isUserInput}>
{props.open && false && (
<>
<pre className="overflow-x-scroll">
diff --git a/extension/react-app/src/components/UserInputContainer.tsx b/extension/react-app/src/components/UserInputContainer.tsx
new file mode 100644
index 00000000..7d6f0d4e
--- /dev/null
+++ b/extension/react-app/src/components/UserInputContainer.tsx
@@ -0,0 +1,57 @@
+import React from "react";
+import ReactMarkdown from "react-markdown";
+import styled from "styled-components";
+import { buttonColor, secondaryDark } from ".";
+import HeaderButtonWithText from "./HeaderButtonWithText";
+import { Play, XMark } from "@styled-icons/heroicons-outline";
+import { RootStore } from "../redux/store";
+import { useSelector } from "react-redux";
+
+interface UserInputContainerProps {
+ onDelete: () => void;
+ children: string;
+}
+
+const StyledDiv = styled.div`
+ background-color: rgb(50 50 50);
+ padding: 8px;
+ padding-left: 16px;
+ border-bottom: 1px solid white;
+ border-top: 1px solid white;
+ font-size: 13px;
+ display: flex;
+ align-items: center;
+ gap: 2px;
+`;
+
+const DeleteButton = styled.button`
+ position: absolute;
+ top: 0;
+ right: 0;
+ background: none;
+ border: none;
+ cursor: pointer;
+ margin-left: auto;
+`;
+
+const UserInputContainer: React.FC<UserInputContainerProps> = ({
+ children,
+ onDelete,
+}) => {
+ return (
+ <StyledDiv>
+ {children}
+ <HeaderButtonWithText
+ onClick={(e) => {
+ e.stopPropagation();
+ onDelete();
+ }}
+ text="Delete"
+ >
+ <XMark size="1.6em" onClick={onDelete} />
+ </HeaderButtonWithText>
+ </StyledDiv>
+ );
+};
+
+export default UserInputContainer;
diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts
index fc94c51f..429a7df5 100644
--- a/extension/react-app/src/components/index.ts
+++ b/extension/react-app/src/components/index.ts
@@ -1,7 +1,7 @@
import styled, { keyframes } from "styled-components";
export const defaultBorderRadius = "5px";
-export const secondaryDark = "rgb(37 37 38)";
+export const secondaryDark = "rgb(42 42 42)";
export const vscBackground = "rgb(30 30 30)";
export const vscBackgroundTransparent = "#1e1e1ede";
export const buttonColor = "rgb(113 28 59)";
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index cccd184e..40256f86 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -20,6 +20,7 @@ import { useSelector } from "react-redux";
import { RootStore } from "../redux/store";
import LoadingCover from "../components/LoadingCover";
import { postVscMessage } from "../vscode";
+import UserInputContainer from "../components/UserInputContainer";
const TopGUIDiv = styled.div`
overflow: hidden;
@@ -152,6 +153,14 @@ function GUI(props: GUIProps) {
setHistory(state.history);
setHighlightedRanges(state.highlighted_ranges);
setUserInputQueue(state.user_input_queue);
+ setAvailableSlashCommands(
+ state.slash_commands.map((c: any) => {
+ return {
+ name: `/${c.name}`,
+ description: c.description,
+ };
+ })
+ );
setStepsOpen((prev) => {
const nextStepsOpen = [...prev];
for (
@@ -168,17 +177,6 @@ function GUI(props: GUIProps) {
scrollToBottom();
}
});
- client?.onAvailableSlashCommands((commands) => {
- console.log("Received available slash commands: ", commands);
- setAvailableSlashCommands(
- commands.map((c) => {
- return {
- name: "/" + c.name,
- description: c.description,
- };
- })
- );
- });
}, [client]);
useEffect(() => {
@@ -283,7 +281,15 @@ function GUI(props: GUIProps) {
</>
)}
{history?.timeline.map((node: HistoryNode, index: number) => {
- return (
+ return node.step.name === "User Input" ? (
+ <UserInputContainer
+ onDelete={() => {
+ client?.deleteAtIndex(index);
+ }}
+ >
+ {node.step.description as string}
+ </UserInputContainer>
+ ) : (
<StepContainer
isLast={index === history.timeline.length - 1}
isFirst={index === 0}
@@ -302,9 +308,6 @@ function GUI(props: GUIProps) {
}}
inFuture={index > history?.current_index}
historyNode={node}
- onRefinement={(input: string) => {
- client?.sendRefinementInput(input, index);
- }}
onReverse={() => {
client?.reverseToIndex(index);
}}