From f53768612b1e2268697b5444e502032ef9f3fb3c Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Tue, 23 May 2023 23:45:12 -0400 Subject: copying from old repo --- extension/src/bridge.ts | 292 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 extension/src/bridge.ts (limited to 'extension/src/bridge.ts') diff --git a/extension/src/bridge.ts b/extension/src/bridge.ts new file mode 100644 index 00000000..3e21a205 --- /dev/null +++ b/extension/src/bridge.ts @@ -0,0 +1,292 @@ +import fetch from "node-fetch"; +import * as path from "path"; +import * as vscode from "vscode"; +import { + Configuration, + DebugApi, + RangeInFile, + SerializedDebugContext, + UnittestApi, +} from "./client"; +import { convertSingleToDoubleQuoteJSON } from "./util/util"; +import { getExtensionUri } from "./util/vscode"; +const axios = require("axios").default; +const util = require("util"); +const exec = util.promisify(require("child_process").exec); + +const configuration = new Configuration({ + basePath: get_api_url(), + fetchApi: fetch as any, + middleware: [ + { + pre: async (context) => { + // If there is a SerializedDebugContext in the body, add the files for the filesystem + context.init.body; + + // Add the VS Code Machine Code Header + context.init.headers = { + ...context.init.headers, + "x-vsc-machine-id": vscode.env.machineId, + }; + }, + }, + ], +}); +export const debugApi = new DebugApi(configuration); +export const unittestApi = new UnittestApi(configuration); + +function get_python_path() { + return path.join(getExtensionUri().fsPath, ".."); +} + +export function get_api_url() { + let extensionUri = getExtensionUri(); + let configFile = path.join(extensionUri.fsPath, "config/config.json"); + let config = require(configFile); + + if (config.API_URL) { + return config.API_URL; + } + return "http://localhost:8000"; +} +const API_URL = get_api_url(); + +export function getContinueServerUrl() { + return ( + vscode.workspace.getConfiguration("continue").get("serverUrl") || + "http://localhost:8000" + ); +} + +function build_python_command(cmd: string): string { + return `cd ${get_python_path()} && source env/bin/activate && ${cmd}`; +} + +function listToCmdLineArgs(list: string[]): string { + return list.map((el) => `"$(echo "${el}")"`).join(" "); +} + +export async function runPythonScript( + scriptName: string, + args: string[] +): Promise { + // TODO: Need to make sure that the path to poetry is in the PATH and that it is installed in the first place. Realistically also need to install npm in some cases. + const command = `export PATH="$PATH:/opt/homebrew/bin" && cd ${path.join( + getExtensionUri().fsPath, + "scripts" + )} && source env/bin/activate && python3 ${scriptName} ${listToCmdLineArgs( + args + )}`; + + const { stdout, stderr } = await exec(command); + + try { + let jsonString = stdout.substring( + stdout.indexOf("{"), + stdout.lastIndexOf("}") + 1 + ); + jsonString = convertSingleToDoubleQuoteJSON(jsonString); + return JSON.parse(jsonString); + } catch (e) { + if (stderr) { + throw new Error(stderr); + } else { + throw new Error("Failed to parse JSON: " + e); + } + } +} + +function parseStdout( + stdout: string, + key: string, + until_end: boolean = false +): string { + const prompt = `${key}=`; + let lines = stdout.split("\n"); + + let value: string = ""; + for (let i = 0; i < lines.length; i++) { + if (lines[i].startsWith(prompt)) { + if (until_end) { + return lines.slice(i).join("\n").substring(prompt.length); + } else { + return lines[i].substring(prompt.length); + } + } + } + return ""; +} + +export async function askQuestion( + question: string, + workspacePath: string +): Promise<{ answer: string; range: vscode.Range; filename: string }> { + const command = build_python_command( + `python3 ${path.join( + get_python_path(), + "ask.py" + )} ask ${workspacePath} "${question}"` + ); + + const { stdout, stderr } = await exec(command); + if (stderr) { + throw new Error(stderr); + } + // Use the output + const answer = parseStdout(stdout, "Answer"); + const filename = parseStdout(stdout, "Filename"); + const startLineno = parseInt(parseStdout(stdout, "Start lineno")); + const endLineno = parseInt(parseStdout(stdout, "End lineno")); + const range = new vscode.Range( + new vscode.Position(startLineno, 0), + new vscode.Position(endLineno, 0) + ); + if (answer && filename && startLineno && endLineno) { + return { answer, filename, range }; + } else { + throw new Error("Error: No answer found"); + } +} + +export async function apiRequest( + endpoint: string, + options: { + method?: string; + query?: { [key: string]: any }; + body?: { [key: string]: any }; + } +): Promise { + let defaults = { + method: "GET", + query: {}, + body: {}, + }; + options = Object.assign(defaults, options); // Second takes over first + if (endpoint.startsWith("/")) endpoint = endpoint.substring(1); + console.log("API request: ", options.body); + + let resp; + try { + resp = await axios({ + method: options.method, + url: `${API_URL}/${endpoint}`, + data: options.body, + params: options.query, + headers: { + "x-vsc-machine-id": vscode.env.machineId, + }, + }); + } catch (err) { + console.log("Error: ", err); + throw err; + } + + return resp.data; +} + +// Write a docstring for the most specific function or class at the current line in the given file +export async function writeDocstringForFunction( + filename: string, + position: vscode.Position +): Promise<{ lineno: number; docstring: string }> { + let resp = await apiRequest("docstring/forline", { + query: { + filecontents: ( + await vscode.workspace.fs.readFile(vscode.Uri.file(filename)) + ).toString(), + lineno: position.line.toString(), + }, + }); + + const lineno = resp.lineno; + const docstring = resp.completion; + if (lineno && docstring) { + return { lineno, docstring }; + } else { + throw new Error("Error: No docstring returned"); + } +} + +export async function findSuspiciousCode( + ctx: SerializedDebugContext +): Promise { + if (!ctx.traceback) return []; + let files = await getFileContents( + getFilenamesFromPythonStacktrace(ctx.traceback) + ); + let resp = await debugApi.findSusCodeEndpointDebugFindPost({ + findBody: { + traceback: ctx.traceback, + description: ctx.description, + filesystem: files, + }, + }); + let ranges = resp.response; + if ( + ranges.length <= 1 && + ctx.traceback && + ctx.traceback.includes("AssertionError") + ) { + let parsed_traceback = + await debugApi.parseTracebackEndpointDebugParseTracebackGet({ + traceback: ctx.traceback, + }); + let last_frame = parsed_traceback.frames[0]; + if (!last_frame) return []; + ranges = ( + await runPythonScript("build_call_graph.py", [ + last_frame.filepath, + last_frame.lineno.toString(), + last_frame._function, + ]) + ).value; + } + + return ranges; +} + +export async function writeUnitTestForFunction( + filename: string, + position: vscode.Position +): Promise { + let resp = await apiRequest("unittest/forline", { + method: "POST", + body: { + filecontents: ( + await vscode.workspace.fs.readFile(vscode.Uri.file(filename)) + ).toString(), + lineno: position.line, + userid: vscode.env.machineId, + }, + }); + + return resp.completion; +} + +async function getFileContents( + files: string[] +): Promise<{ [key: string]: string }> { + let contents = await Promise.all( + files.map(async (file: string) => { + return ( + await vscode.workspace.fs.readFile(vscode.Uri.file(file)) + ).toString(); + }) + ); + let fileContents: { [key: string]: string } = {}; + for (let i = 0; i < files.length; i++) { + fileContents[files[i]] = contents[i]; + } + return fileContents; +} + +function getFilenamesFromPythonStacktrace(traceback: string): string[] { + let filenames: string[] = []; + for (let line of traceback.split("\n")) { + let match = line.match(/File "(.*)", line/); + if (match) { + filenames.push(match[1]); + } + } + return filenames; +} -- cgit v1.2.3-70-g09d2 From 5ae9fdcf9aadf57101ecfd4b7635f4325f53d392 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sat, 17 Jun 2023 10:46:54 -0700 Subject: ui details --- .../src/continuedev/libs/llm/proxy_server.py | 2 ++ extension/package-lock.json | 4 ++-- extension/package.json | 2 +- extension/react-app/src/components/ComboBox.tsx | 4 ++-- .../react-app/src/components/StepContainer.tsx | 23 +++++++++++++-------- extension/react-app/src/tabs/gui.tsx | 19 +++++++++++++++++ .../scripts/continuedev-0.1.1-py3-none-any.whl | Bin 84291 -> 84332 bytes extension/src/bridge.ts | 8 +++++++ 8 files changed, 48 insertions(+), 14 deletions(-) (limited to 'extension/src/bridge.ts') diff --git a/continuedev/src/continuedev/libs/llm/proxy_server.py b/continuedev/src/continuedev/libs/llm/proxy_server.py index dd0d3aca..84c94d62 100644 --- a/continuedev/src/continuedev/libs/llm/proxy_server.py +++ b/continuedev/src/continuedev/libs/llm/proxy_server.py @@ -23,12 +23,14 @@ SERVER_URL = "https://proxy-server-l6vsfbzhba-uw.a.run.app" class ProxyServer(LLM): unique_id: str + name: str default_model: Literal["gpt-3.5-turbo", "gpt-4"] def __init__(self, unique_id: str, default_model: Literal["gpt-3.5-turbo", "gpt-4"], system_message: str = None): self.unique_id = unique_id self.default_model = default_model self.system_message = system_message + self.name = default_model @cached_property def __encoding_for_model(self): diff --git a/extension/package-lock.json b/extension/package-lock.json index 92df6a4f..64fa3660 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.50", + "version": "0.0.52", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.50", + "version": "0.0.52", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index a875c82d..bf4f5eb3 100644 --- a/extension/package.json +++ b/extension/package.json @@ -14,7 +14,7 @@ "displayName": "Continue", "pricing": "Free", "description": "Refine code 10x faster", - "version": "0.0.50", + "version": "0.0.52", "publisher": "Continue", "engines": { "vscode": "^1.74.0" diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx index 29f8a53b..e855ebe5 100644 --- a/extension/react-app/src/components/ComboBox.tsx +++ b/extension/react-app/src/components/ComboBox.tsx @@ -124,11 +124,11 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { } else if (event.key === "Tab" && items.length > 0) { setInputValue(items[0].name); event.preventDefault(); - } else if (event.key === "ArrowUp" && !isOpen) { + } else if (event.key === "ArrowUp") { if (positionInHistory == 0) return; setInputValue(history[positionInHistory - 1]); setPositionInHistory((prev) => prev - 1); - } else if (event.key === "ArrowDown" && !isOpen) { + } else if (event.key === "ArrowDown") { if (positionInHistory >= history.length - 1) { setInputValue(""); } else { diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx index 7adbd7c2..4c98b04d 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -31,7 +31,9 @@ interface StepContainerProps { onUserInput: (input: string) => void; onRetry: () => void; onDelete: () => void; - open?: boolean; + open: boolean; + onToggleAll: () => void; + onToggle: () => void; } const MainDiv = styled.div<{ stepDepth: number; inFuture: boolean }>` @@ -81,9 +83,6 @@ const MarkdownPre = styled.pre` const MarkdownCode = styled.code``; function StepContainer(props: StepContainerProps) { - const [open, setOpen] = useState( - typeof props.open === "undefined" ? true : props.open - ); const [isHovered, setIsHovered] = useState(false); const naturalLanguageInputRef = useRef(null); const userInputRef = useRef(null); @@ -119,19 +118,25 @@ function StepContainer(props: StepContainerProps) { }} hidden={props.historyNode.step.hide as any} > - + setOpen((prev) => !prev)} + onClick={(e) => { + if (props.open && e.metaKey) { + props.onToggleAll(); + } else { + props.onToggle(); + } + }} >

- {open ? ( + {props.open ? ( ) : ( @@ -174,8 +179,8 @@ function StepContainer(props: StepContainerProps) { -