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/schema/FileEdit.d.ts | 32 ++++++++++++++++++++++ extension/schema/FileEditWithFullContents.d.ts | 38 ++++++++++++++++++++++++++ extension/schema/Position.d.ts | 16 +++++++++++ extension/schema/Range.d.ts | 24 ++++++++++++++++ extension/schema/RangeInFile.d.ts | 30 ++++++++++++++++++++ extension/schema/Traceback.d.ts | 31 +++++++++++++++++++++ extension/schema/TracebackFrame.d.ts | 20 ++++++++++++++ 7 files changed, 191 insertions(+) create mode 100644 extension/schema/FileEdit.d.ts create mode 100644 extension/schema/FileEditWithFullContents.d.ts create mode 100644 extension/schema/Position.d.ts create mode 100644 extension/schema/Range.d.ts create mode 100644 extension/schema/RangeInFile.d.ts create mode 100644 extension/schema/Traceback.d.ts create mode 100644 extension/schema/TracebackFrame.d.ts (limited to 'extension/schema') diff --git a/extension/schema/FileEdit.d.ts b/extension/schema/FileEdit.d.ts new file mode 100644 index 00000000..b39e3f3f --- /dev/null +++ b/extension/schema/FileEdit.d.ts @@ -0,0 +1,32 @@ +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type FileEdit = FileEdit1; +export type Filepath = string; +export type Line = number; +export type Character = number; +export type Replacement = string; + +export interface FileEdit1 { + filepath: Filepath; + range: Range; + replacement: Replacement; + [k: string]: unknown; +} +/** + * A range in a file. 0-indexed. + */ +export interface Range { + start: Position; + end: Position; + [k: string]: unknown; +} +export interface Position { + line: Line; + character: Character; + [k: string]: unknown; +} diff --git a/extension/schema/FileEditWithFullContents.d.ts b/extension/schema/FileEditWithFullContents.d.ts new file mode 100644 index 00000000..b96cdd3c --- /dev/null +++ b/extension/schema/FileEditWithFullContents.d.ts @@ -0,0 +1,38 @@ +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type FileEditWithFullContents = FileEditWithFullContents1; +export type Filepath = string; +export type Line = number; +export type Character = number; +export type Replacement = string; +export type Filecontents = string; + +export interface FileEditWithFullContents1 { + fileEdit: FileEdit; + fileContents: Filecontents; + [k: string]: unknown; +} +export interface FileEdit { + filepath: Filepath; + range: Range; + replacement: Replacement; + [k: string]: unknown; +} +/** + * A range in a file. 0-indexed. + */ +export interface Range { + start: Position; + end: Position; + [k: string]: unknown; +} +export interface Position { + line: Line; + character: Character; + [k: string]: unknown; +} diff --git a/extension/schema/Position.d.ts b/extension/schema/Position.d.ts new file mode 100644 index 00000000..c9092edd --- /dev/null +++ b/extension/schema/Position.d.ts @@ -0,0 +1,16 @@ +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type Position = Position1; +export type Line = number; +export type Character = number; + +export interface Position1 { + line: Line; + character: Character; + [k: string]: unknown; +} diff --git a/extension/schema/Range.d.ts b/extension/schema/Range.d.ts new file mode 100644 index 00000000..904ed3fe --- /dev/null +++ b/extension/schema/Range.d.ts @@ -0,0 +1,24 @@ +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type Range = Range1; +export type Line = number; +export type Character = number; + +/** + * A range in a file. 0-indexed. + */ +export interface Range1 { + start: Position; + end: Position; + [k: string]: unknown; +} +export interface Position { + line: Line; + character: Character; + [k: string]: unknown; +} diff --git a/extension/schema/RangeInFile.d.ts b/extension/schema/RangeInFile.d.ts new file mode 100644 index 00000000..0dcd3bca --- /dev/null +++ b/extension/schema/RangeInFile.d.ts @@ -0,0 +1,30 @@ +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type RangeInFile = RangeInFile1; +export type Filepath = string; +export type Line = number; +export type Character = number; + +export interface RangeInFile1 { + filepath: Filepath; + range: Range; + [k: string]: unknown; +} +/** + * A range in a file. 0-indexed. + */ +export interface Range { + start: Position; + end: Position; + [k: string]: unknown; +} +export interface Position { + line: Line; + character: Character; + [k: string]: unknown; +} diff --git a/extension/schema/Traceback.d.ts b/extension/schema/Traceback.d.ts new file mode 100644 index 00000000..19bfa3db --- /dev/null +++ b/extension/schema/Traceback.d.ts @@ -0,0 +1,31 @@ +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type Traceback = Traceback1; +export type Filepath = string; +export type Lineno = number; +export type Function = string; +export type Code = string; +export type Frames = TracebackFrame[]; +export type Message = string; +export type ErrorType = string; +export type FullTraceback = string; + +export interface Traceback1 { + frames: Frames; + message: Message; + error_type: ErrorType; + full_traceback?: FullTraceback; + [k: string]: unknown; +} +export interface TracebackFrame { + filepath: Filepath; + lineno: Lineno; + function: Function; + code?: Code; + [k: string]: unknown; +} diff --git a/extension/schema/TracebackFrame.d.ts b/extension/schema/TracebackFrame.d.ts new file mode 100644 index 00000000..f6861218 --- /dev/null +++ b/extension/schema/TracebackFrame.d.ts @@ -0,0 +1,20 @@ +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type TracebackFrame = TracebackFrame1; +export type Filepath = string; +export type Lineno = number; +export type Function = string; +export type Code = string; + +export interface TracebackFrame1 { + filepath: Filepath; + lineno: Lineno; + function: Function; + code?: Code; + [k: string]: unknown; +} -- cgit v1.2.3-70-g09d2 From e7fd1cd977c04643a11989f0bcefe6f573ab994a Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sat, 27 May 2023 15:58:34 -0400 Subject: Added History classes for JSON Schema generation --- .../src/continuedev/models/generate_json_schema.py | 3 + extension/package.json | 2 +- extension/schema/History.d.ts | 41 + extension/schema/HistoryNode.d.ts | 31 + .../scripts/continuedev-0.1.0-py3-none-any.whl | Bin 61142 -> 51468 bytes schema/json/History.json | 73 ++ schema/json/HistoryNode.json | 51 + schema/openapi.json | 1027 ++++++++++++++++++++ 8 files changed, 1227 insertions(+), 1 deletion(-) create mode 100644 extension/schema/History.d.ts create mode 100644 extension/schema/HistoryNode.d.ts create mode 100644 schema/json/History.json create mode 100644 schema/json/HistoryNode.json create mode 100644 schema/openapi.json (limited to 'extension/schema') diff --git a/continuedev/src/continuedev/models/generate_json_schema.py b/continuedev/src/continuedev/models/generate_json_schema.py index da78dfac..07337029 100644 --- a/continuedev/src/continuedev/models/generate_json_schema.py +++ b/continuedev/src/continuedev/models/generate_json_schema.py @@ -1,6 +1,7 @@ from .main import * from .filesystem import RangeInFile, FileEdit from .filesystem_edit import FileEditWithFullContents +from ..core.main import History, HistoryNode from pydantic import schema_json_of import os @@ -10,6 +11,8 @@ MODELS_TO_GENERATE = [ RangeInFile, FileEdit ] + [ FileEditWithFullContents +] + [ + History, HistoryNode ] RENAMES = { diff --git a/extension/package.json b/extension/package.json index d957e071..3f9e59ff 100644 --- a/extension/package.json +++ b/extension/package.json @@ -166,7 +166,7 @@ "package": "cp ./config/prod_config.json ./config/config.json && npm run compile && mkdir -p ./build && vsce package --out ./build && chmod 777 ./build/continue-0.0.1.vsix && cp ./config/dev_config.json ./config/config.json", "full-package": "cd ../continuedev && poetry build && cp ./dist/continuedev-0.1.0-py3-none-any.whl ../extension/scripts/continuedev-0.1.0-py3-none-any.whl && cd ../extension && npm run typegen && npm run clientgen && cd react-app && npm run build && cd .. && npm run package", "install-extension": "code --install-extension ./build/continue-0.0.1.vsix", - "uninstall": "code --uninstall-extension Continue.continue", + "uninstall": "code --uninstall-extension .continue", "reinstall": "rm -rf ./build && npm run package && npm run uninstall && npm run install-extension" }, "devDependencies": { diff --git a/extension/schema/History.d.ts b/extension/schema/History.d.ts new file mode 100644 index 00000000..508deaf0 --- /dev/null +++ b/extension/schema/History.d.ts @@ -0,0 +1,41 @@ +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type History = History1; +export type Name = string; +export type Hide = boolean; +export type SystemMessage = string; +export type Depth = number; +export type Timeline = HistoryNode[]; +export type CurrentIndex = number; + +/** + * A history of steps taken and their results + */ +export interface History1 { + timeline: Timeline; + current_index: CurrentIndex; + [k: string]: unknown; +} +/** + * A point in history, a list of which make up History + */ +export interface HistoryNode { + step: Step; + observation?: Observation; + depth: Depth; + [k: string]: unknown; +} +export interface Step { + name?: Name; + hide?: Hide; + system_message?: SystemMessage; + [k: string]: unknown; +} +export interface Observation { + [k: string]: unknown; +} diff --git a/extension/schema/HistoryNode.d.ts b/extension/schema/HistoryNode.d.ts new file mode 100644 index 00000000..c1507270 --- /dev/null +++ b/extension/schema/HistoryNode.d.ts @@ -0,0 +1,31 @@ +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type HistoryNode = HistoryNode1; +export type Name = string; +export type Hide = boolean; +export type SystemMessage = string; +export type Depth = number; + +/** + * A point in history, a list of which make up History + */ +export interface HistoryNode1 { + step: Step; + observation?: Observation; + depth: Depth; + [k: string]: unknown; +} +export interface Step { + name?: Name; + hide?: Hide; + system_message?: SystemMessage; + [k: string]: unknown; +} +export interface Observation { + [k: string]: unknown; +} diff --git a/extension/scripts/continuedev-0.1.0-py3-none-any.whl b/extension/scripts/continuedev-0.1.0-py3-none-any.whl index 15787c59..68457b3e 100644 Binary files a/extension/scripts/continuedev-0.1.0-py3-none-any.whl and b/extension/scripts/continuedev-0.1.0-py3-none-any.whl differ diff --git a/schema/json/History.json b/schema/json/History.json new file mode 100644 index 00000000..7691c7dd --- /dev/null +++ b/schema/json/History.json @@ -0,0 +1,73 @@ +{ + "title": "History", + "$ref": "#/definitions/continuedev__src__continuedev__core__main__History", + "definitions": { + "Step": { + "title": "Step", + "type": "object", + "properties": { + "name": { + "title": "Name", + "type": "string" + }, + "hide": { + "title": "Hide", + "default": false, + "type": "boolean" + }, + "system_message": { + "title": "System Message", + "type": "string" + } + } + }, + "Observation": { + "title": "Observation", + "type": "object", + "properties": {} + }, + "HistoryNode": { + "title": "HistoryNode", + "description": "A point in history, a list of which make up History", + "type": "object", + "properties": { + "step": { + "$ref": "#/definitions/Step" + }, + "observation": { + "$ref": "#/definitions/Observation" + }, + "depth": { + "title": "Depth", + "type": "integer" + } + }, + "required": [ + "step", + "depth" + ] + }, + "continuedev__src__continuedev__core__main__History": { + "title": "History", + "description": "A history of steps taken and their results", + "type": "object", + "properties": { + "timeline": { + "title": "Timeline", + "type": "array", + "items": { + "$ref": "#/definitions/HistoryNode" + } + }, + "current_index": { + "title": "Current Index", + "type": "integer" + } + }, + "required": [ + "timeline", + "current_index" + ] + } + } +} \ No newline at end of file diff --git a/schema/json/HistoryNode.json b/schema/json/HistoryNode.json new file mode 100644 index 00000000..f58b8038 --- /dev/null +++ b/schema/json/HistoryNode.json @@ -0,0 +1,51 @@ +{ + "title": "HistoryNode", + "$ref": "#/definitions/continuedev__src__continuedev__core__main__HistoryNode", + "definitions": { + "Step": { + "title": "Step", + "type": "object", + "properties": { + "name": { + "title": "Name", + "type": "string" + }, + "hide": { + "title": "Hide", + "default": false, + "type": "boolean" + }, + "system_message": { + "title": "System Message", + "type": "string" + } + } + }, + "Observation": { + "title": "Observation", + "type": "object", + "properties": {} + }, + "continuedev__src__continuedev__core__main__HistoryNode": { + "title": "HistoryNode", + "description": "A point in history, a list of which make up History", + "type": "object", + "properties": { + "step": { + "$ref": "#/definitions/Step" + }, + "observation": { + "$ref": "#/definitions/Observation" + }, + "depth": { + "title": "Depth", + "type": "integer" + } + }, + "required": [ + "step", + "depth" + ] + } + } +} \ No newline at end of file diff --git a/schema/openapi.json b/schema/openapi.json new file mode 100644 index 00000000..8880fd20 --- /dev/null +++ b/schema/openapi.json @@ -0,0 +1,1027 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Continue API", + "description": "Continue API", + "version": "1.0" + }, + "paths": { + "/debug/run": { + "post": { + "tags": ["debug"], + "summary": "Run", + "description": "Returns boolean indicating whether error was found, edited, and solved, or not all of these.", + "operationId": "run_debug_run_post", + "parameters": [ + { + "required": true, + "schema": { + "title": "Filepath", + "type": "string" + }, + "name": "filepath", + "in": "query" + }, + { + "required": false, + "schema": { + "title": "Make Edit", + "type": "boolean", + "default": false + }, + "name": "make_edit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/debug/inline": { + "post": { + "tags": ["debug"], + "summary": "Inline", + "operationId": "inline_debug_inline_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InlineBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CompletionResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/debug/suggestion": { + "get": { + "tags": ["debug"], + "summary": "Suggestion", + "operationId": "suggestion_debug_suggestion_get", + "parameters": [ + { + "required": true, + "schema": { + "title": "Traceback", + "type": "string" + }, + "name": "traceback", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CompletionResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/debug/list": { + "post": { + "tags": ["debug"], + "summary": "Listten", + "operationId": "listten_debug_list_post", + "parameters": [ + { + "required": false, + "schema": { + "title": "X-Vsc-Machine-Id", + "type": "string", + "default": "anonymous" + }, + "name": "x-vsc-machine-id", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SerializedDebugContext" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CompletionResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/debug/explain": { + "post": { + "tags": ["debug"], + "summary": "Explain", + "operationId": "explain_debug_explain_post", + "parameters": [ + { + "required": false, + "schema": { + "title": "X-Vsc-Machine-Id", + "type": "string", + "default": "anonymous" + }, + "name": "x-vsc-machine-id", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SerializedDebugContext" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExplainResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/debug/edit": { + "post": { + "tags": ["debug"], + "summary": "Edit Endpoint", + "operationId": "edit_endpoint_debug_edit_post", + "parameters": [ + { + "required": false, + "schema": { + "title": "X-Vsc-Machine-Id", + "type": "string", + "default": "anonymous" + }, + "name": "x-vsc-machine-id", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SerializedDebugContext" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EditResp" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/debug/find": { + "post": { + "tags": ["debug"], + "summary": "Find Sus Code Endpoint", + "operationId": "find_sus_code_endpoint_debug_find_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FindBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FindResp" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/debug/parse_traceback": { + "get": { + "tags": ["debug"], + "summary": "Parse Traceback Endpoint", + "operationId": "parse_traceback_endpoint_debug_parse_traceback_get", + "parameters": [ + { + "required": true, + "schema": { + "title": "Traceback", + "type": "string" + }, + "name": "traceback", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Traceback" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/debug/find_docs": { + "get": { + "tags": ["debug"], + "summary": "Find Docs Endpoint", + "operationId": "find_docs_endpoint_debug_find_docs_get", + "parameters": [ + { + "required": true, + "schema": { + "title": "Traceback", + "type": "string" + }, + "name": "traceback", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OptionalCompletionResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/docstring/forline": { + "get": { + "tags": ["docstring"], + "summary": "Forline", + "description": "Write a docstring for a function at a line number", + "operationId": "forline_docstring_forline_get", + "parameters": [ + { + "required": true, + "schema": { + "title": "Filecontents", + "type": "string" + }, + "name": "filecontents", + "in": "query" + }, + { + "required": true, + "schema": { + "title": "Lineno", + "type": "integer" + }, + "name": "lineno", + "in": "query" + }, + { + "required": false, + "schema": { + "title": "Format", + "type": "string", + "default": "google" + }, + "name": "format", + "in": "query" + }, + { + "required": false, + "schema": { + "title": "X-Vsc-Machine-Id", + "type": "string", + "default": "anonymous" + }, + "name": "x-vsc-machine-id", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/unittest/forline": { + "post": { + "tags": ["unittest"], + "summary": "Forline", + "description": "Write unit test for the function encapsulating the given line number.", + "operationId": "forline_unittest_forline_post", + "parameters": [ + { + "required": false, + "schema": { + "title": "X-Vsc-Machine-Id", + "type": "string", + "default": "anonymous" + }, + "name": "x-vsc-machine-id", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FilePosition" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CompletionResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/unittest/failingtest": { + "post": { + "tags": ["unittest"], + "summary": "Failingtest", + "description": "Write a failing test for the function encapsulating the given line number.", + "operationId": "failingtest_unittest_failingtest_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FailingTestBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CompletionResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/chat/test": { + "get": { + "tags": ["chat"], + "summary": "Test", + "operationId": "test_chat_test_get", + "parameters": [ + { + "required": true, + "schema": { + "title": "Prompt", + "type": "string" + }, + "name": "prompt", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/chat/complete": { + "post": { + "tags": ["chat"], + "summary": "Complete", + "operationId": "complete_chat_complete_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatHistory" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/test": { + "get": { + "summary": "Test", + "operationId": "test_test_get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + } + }, + "components": { + "schemas": { + "ChatHistory": { + "title": "ChatHistory", + "required": ["messages"], + "type": "object", + "properties": { + "messages": { + "title": "Messages", + "type": "array", + "items": { + "$ref": "#/components/schemas/ChatMessage" + } + } + } + }, + "ChatMessage": { + "title": "ChatMessage", + "required": ["role", "content"], + "type": "object", + "properties": { + "role": { + "title": "Role", + "type": "string" + }, + "content": { + "title": "Content", + "type": "string" + } + } + }, + "CompletionResponse": { + "title": "CompletionResponse", + "required": ["completion"], + "type": "object", + "properties": { + "completion": { + "title": "Completion", + "type": "string" + } + } + }, + "EditResp": { + "title": "EditResp", + "required": ["completion"], + "type": "object", + "properties": { + "completion": { + "title": "Completion", + "type": "array", + "items": { + "$ref": "#/components/schemas/FileEdit" + } + } + } + }, + "ExplainResponse": { + "title": "ExplainResponse", + "required": ["completion"], + "type": "object", + "properties": { + "completion": { + "title": "Completion", + "type": "string" + } + } + }, + "FailingTestBody": { + "title": "FailingTestBody", + "required": ["description", "fp"], + "type": "object", + "properties": { + "description": { + "title": "Description", + "type": "string" + }, + "fp": { + "$ref": "#/components/schemas/FilePosition" + } + }, + "description": "A failing test body." + }, + "FileEdit": { + "title": "FileEdit", + "required": ["filepath", "range", "replacement"], + "type": "object", + "properties": { + "filepath": { + "title": "Filepath", + "type": "string" + }, + "range": { + "$ref": "#/components/schemas/Range" + }, + "replacement": { + "title": "Replacement", + "type": "string" + } + }, + "additionalProperties": false + }, + "FilePosition": { + "title": "FilePosition", + "required": ["filecontents", "lineno"], + "type": "object", + "properties": { + "filecontents": { + "title": "Filecontents", + "type": "string" + }, + "lineno": { + "title": "Lineno", + "type": "integer" + } + }, + "description": "A position in a file." + }, + "FindBody": { + "title": "FindBody", + "required": ["traceback", "filesystem"], + "type": "object", + "properties": { + "traceback": { + "title": "Traceback", + "type": "string" + }, + "filesystem": { + "title": "Filesystem", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": { + "title": "Description", + "type": "string" + } + } + }, + "FindResp": { + "title": "FindResp", + "required": ["response"], + "type": "object", + "properties": { + "response": { + "title": "Response", + "type": "array", + "items": { + "$ref": "#/components/schemas/RangeInFile" + } + } + } + }, + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + }, + "InlineBody": { + "title": "InlineBody", + "required": ["filecontents", "startline", "endline"], + "type": "object", + "properties": { + "filecontents": { + "title": "Filecontents", + "type": "string" + }, + "startline": { + "title": "Startline", + "type": "integer" + }, + "endline": { + "title": "Endline", + "type": "integer" + }, + "traceback": { + "title": "Traceback", + "type": "string", + "default": "" + } + } + }, + "OptionalCompletionResponse": { + "title": "OptionalCompletionResponse", + "type": "object", + "properties": { + "completion": { + "title": "Completion", + "type": "string" + } + } + }, + "Position": { + "title": "Position", + "required": ["line", "character"], + "type": "object", + "properties": { + "line": { + "title": "Line", + "type": "integer" + }, + "character": { + "title": "Character", + "type": "integer" + } + }, + "additionalProperties": false + }, + "ProgrammingLangauge": { + "title": "ProgrammingLangauge", + "enum": ["python", "javascript", "typescript"], + "type": "string", + "description": "An enumeration." + }, + "Range": { + "title": "Range", + "required": ["start", "end"], + "type": "object", + "properties": { + "start": { + "$ref": "#/components/schemas/Position" + }, + "end": { + "$ref": "#/components/schemas/Position" + } + }, + "additionalProperties": false, + "description": "A range in a file. 0-indexed." + }, + "RangeInFile": { + "title": "RangeInFile", + "required": ["filepath", "range"], + "type": "object", + "properties": { + "filepath": { + "title": "Filepath", + "type": "string" + }, + "range": { + "$ref": "#/components/schemas/Range" + } + }, + "additionalProperties": false + }, + "SerializedDebugContext": { + "title": "SerializedDebugContext", + "required": ["ranges_in_files", "filesystem"], + "type": "object", + "properties": { + "traceback": { + "title": "Traceback", + "type": "string" + }, + "ranges_in_files": { + "title": "Ranges In Files", + "type": "array", + "items": { + "$ref": "#/components/schemas/RangeInFile" + } + }, + "filesystem": { + "title": "Filesystem", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": { + "title": "Description", + "type": "string" + } + } + }, + "Traceback": { + "title": "Traceback", + "required": ["frames", "message", "error_type", "language"], + "type": "object", + "properties": { + "frames": { + "title": "Frames", + "type": "array", + "items": { + "$ref": "#/components/schemas/TracebackFrame" + } + }, + "message": { + "title": "Message", + "type": "string" + }, + "error_type": { + "title": "Error Type", + "type": "string" + }, + "language": { + "$ref": "#/components/schemas/ProgrammingLangauge" + }, + "full_traceback": { + "title": "Full Traceback", + "type": "string" + } + }, + "additionalProperties": false + }, + "TracebackFrame": { + "title": "TracebackFrame", + "required": ["filepath", "lineno", "function"], + "type": "object", + "properties": { + "filepath": { + "title": "Filepath", + "type": "string" + }, + "lineno": { + "title": "Lineno", + "type": "integer" + }, + "function": { + "title": "Function", + "type": "string" + }, + "code": { + "title": "Code", + "type": "string" + } + }, + "additionalProperties": false + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ] + } + }, + "msg": { + "title": "Message", + "type": "string" + }, + "type": { + "title": "Error Type", + "type": "string" + } + } + } + } + } +} -- cgit v1.2.3-70-g09d2 From 056497801039c1b8f5d4600531f5c90dbd375a38 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 28 May 2023 00:40:10 -0400 Subject: READMEs --- README.md | 7 +------ continuedev/README.md | 8 ++++++++ extension/DEV_README.md | 7 +++++++ extension/examples/README.md | 3 +++ extension/react-app/README.md | 3 +++ extension/schema/README.md | 3 +++ 6 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 extension/DEV_README.md create mode 100644 extension/examples/README.md create mode 100644 extension/react-app/README.md create mode 100644 extension/schema/README.md (limited to 'extension/schema') diff --git a/README.md b/README.md index 18525fcd..dc1ad7de 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,6 @@ # Continue -Try out latest version: - -- `cd extension` -- `npm run package` -- `cd build` -- `code --install-extension continue-0.0.1.vsix` +[Download for VS Code](https://marketplace.visualstudio.com/items?itemName=Continue.continue) Resources diff --git a/continuedev/README.md b/continuedev/README.md index 5af08e24..5658e8de 100644 --- a/continuedev/README.md +++ b/continuedev/README.md @@ -1,3 +1,7 @@ +# Continue + +Continue is a Python library for automating repetitive sequences of software development tasks using language models. Using our VS Code extension, you can build, run, and refine these recipes as they natively interact with your codebase. Download on [our GitHub](https://github.com/continuedev/continue). + ## Steps to start - `cd continue/continue` @@ -17,3 +21,7 @@ Same steps, then `uvicorn continue.src.server.main:app --reload`. ## To build Run `poetry build` and it will output wheel and tarball files in `./dist`. + +## Writing Steps + +See the `src/continuedev/libs/steps` folder for examples of writing a Continue step. diff --git a/extension/DEV_README.md b/extension/DEV_README.md new file mode 100644 index 00000000..7049da45 --- /dev/null +++ b/extension/DEV_README.md @@ -0,0 +1,7 @@ +# Continue VS Code Extension + +This is the Continue VS Code Extension. Its primary jobs are + +1. Implement the IDE side of the Continue IDE protocol, allowing a Continue server to interact natively in an IDE. This happens in `src/continueIdeClient.ts`. +2. Open the Continue React app in a side panel. The React app's source code lives in the `react-app` directory. The panel is opened by the `continue.openDebugPanel` command, as defined in `src/commands.ts`. +3. Run a Continue server in the background, which connects to both the IDE protocol and the React app. The server is launched in `src/activation/environmentSetup.ts` by calling Python code that lives in `scripts/` (unless extension settings define a server URL other than localhost:8000, in which case the extension will just connect to that). diff --git a/extension/examples/README.md b/extension/examples/README.md new file mode 100644 index 00000000..c95b9220 --- /dev/null +++ b/extension/examples/README.md @@ -0,0 +1,3 @@ +# Examples + +This folder contains example code used in Continue demos. diff --git a/extension/react-app/README.md b/extension/react-app/README.md new file mode 100644 index 00000000..006b6b11 --- /dev/null +++ b/extension/react-app/README.md @@ -0,0 +1,3 @@ +# Continue React App + +The Continue React app is a notebook-like interface to the Continue server. It allows the user to submit arbitrary text input, then communicates with the server to takes steps, which are displayed as a sequence of editable cells. The React app should sit beside an IDE, as in the VS Code extension. diff --git a/extension/schema/README.md b/extension/schema/README.md new file mode 100644 index 00000000..9c97c0eb --- /dev/null +++ b/extension/schema/README.md @@ -0,0 +1,3 @@ +# Schema + +These are files autogenerated by `npm run typegen`. They come originally from the `continuedev` Python package's Pydantic types. -- cgit v1.2.3-70-g09d2 From cf9d8c40f480be22c1cfd0493177b5a61adf8d0f Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Mon, 26 Jun 2023 17:41:12 -0700 Subject: syntax highlighting lang auto detection --- extension/react-app/package-lock.json | 219 ---------------------- extension/react-app/src/components/CodeBlock.tsx | 54 +++++- extension/react-app/src/components/StyledCode.tsx | 2 +- extension/schema/History.d.ts | 29 +++ extension/schema/HistoryNode.d.ts | 29 +++ schema/json/History.json | 80 ++++++++ schema/json/HistoryNode.json | 80 ++++++++ 7 files changed, 270 insertions(+), 223 deletions(-) (limited to 'extension/schema') diff --git a/extension/react-app/package-lock.json b/extension/react-app/package-lock.json index 4efdd1da..85b8633b 100644 --- a/extension/react-app/package-lock.json +++ b/extension/react-app/package-lock.json @@ -674,59 +674,6 @@ "node": ">= 8" } }, - "node_modules/@redis/bloom": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", - "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/client": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.8.tgz", - "integrity": "sha512-xzElwHIO6rBAqzPeVnCzgvrnBEcFL1P0w8P65VNLRkdVW8rOE58f52hdj0BDgmsdOm4f1EoXPZtH4Fh7M/qUpw==", - "dependencies": { - "cluster-key-slot": "1.1.2", - "generic-pool": "3.9.0", - "yallist": "4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@redis/graph": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", - "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/json": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", - "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/search": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.3.tgz", - "integrity": "sha512-4Dg1JjvCevdiCBTZqjhKkGoC5/BcB7k9j99kdMnaXFXg8x4eyOIVg9487CMv7/BUVkFLZCaIh8ead9mU15DNng==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/time-series": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", - "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, "node_modules/@styled-icons/heroicons-outline": { "version": "10.47.0", "resolved": "https://registry.npmjs.org/@styled-icons/heroicons-outline/-/heroicons-outline-10.47.0.tgz", @@ -1345,27 +1292,6 @@ "node": ">= 6" } }, - "node_modules/classifier": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/classifier/-/classifier-0.1.0.tgz", - "integrity": "sha512-lHoacZqTxberxbsaT/bDkvUicTl6nVTqnM5X6PhCTCg6Y3uhd/lWqbtMvHwe0W0vGkPWCVw5NTUTi3SOlccaSA==", - "deprecated": "Package no longer supported. Contact support@npmjs.com for more info.", - "dependencies": { - "redis": ">=0.7.0", - "underscore": ">=1.1.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/cluster-key-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", - "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -1721,14 +1647,6 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "node_modules/generic-pool": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", - "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", - "engines": { - "node": ">= 4" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -2026,22 +1944,6 @@ "node": ">=6" } }, - "node_modules/language-classifier": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/language-classifier/-/language-classifier-0.0.1.tgz", - "integrity": "sha512-myU10NLx/dfATa7b0NJiycU4jlU15fMLcnfXYEO6NPMhH1vHYKMp9eoRZaQMDTu3bz25bD31Q9klsf26oOW1BQ==", - "dependencies": { - "classifier": "~0.1.0" - } - }, - "node_modules/language-detect": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/language-detect/-/language-detect-1.1.0.tgz", - "integrity": "sha512-2kXHOATTovlwlh1LJE21DLyGiuvX6bK8CYw9kEyui2FeNBV3EYD2OE9h1ChuWNGXe/TGcm7PqpK/32S614R1Kg==", - "dependencies": { - "language-classifier": "0.0.1" - } - }, "node_modules/lilconfig": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", @@ -3068,19 +2970,6 @@ "node": ">=8.10.0" } }, - "node_modules/redis": { - "version": "4.6.7", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.7.tgz", - "integrity": "sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw==", - "dependencies": { - "@redis/bloom": "1.2.0", - "@redis/client": "1.5.8", - "@redis/graph": "1.1.0", - "@redis/json": "1.0.4", - "@redis/search": "1.1.3", - "@redis/time-series": "1.0.4" - } - }, "node_modules/refractor": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", @@ -3408,11 +3297,6 @@ "node": ">=4.2.0" } }, - "node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" - }, "node_modules/unified": { "version": "10.1.2", "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", @@ -3661,11 +3545,6 @@ "node": ">=0.4" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", @@ -4049,46 +3928,6 @@ "fastq": "^1.6.0" } }, - "@redis/bloom": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", - "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", - "requires": {} - }, - "@redis/client": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.8.tgz", - "integrity": "sha512-xzElwHIO6rBAqzPeVnCzgvrnBEcFL1P0w8P65VNLRkdVW8rOE58f52hdj0BDgmsdOm4f1EoXPZtH4Fh7M/qUpw==", - "requires": { - "cluster-key-slot": "1.1.2", - "generic-pool": "3.9.0", - "yallist": "4.0.0" - } - }, - "@redis/graph": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", - "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", - "requires": {} - }, - "@redis/json": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", - "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", - "requires": {} - }, - "@redis/search": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.3.tgz", - "integrity": "sha512-4Dg1JjvCevdiCBTZqjhKkGoC5/BcB7k9j99kdMnaXFXg8x4eyOIVg9487CMv7/BUVkFLZCaIh8ead9mU15DNng==", - "requires": {} - }, - "@redis/time-series": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", - "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", - "requires": {} - }, "@styled-icons/heroicons-outline": { "version": "10.47.0", "resolved": "https://registry.npmjs.org/@styled-icons/heroicons-outline/-/heroicons-outline-10.47.0.tgz", @@ -4484,20 +4323,6 @@ } } }, - "classifier": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/classifier/-/classifier-0.1.0.tgz", - "integrity": "sha512-lHoacZqTxberxbsaT/bDkvUicTl6nVTqnM5X6PhCTCg6Y3uhd/lWqbtMvHwe0W0vGkPWCVw5NTUTi3SOlccaSA==", - "requires": { - "redis": ">=0.7.0", - "underscore": ">=1.1.0" - } - }, - "cluster-key-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", - "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==" - }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -4770,11 +4595,6 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "generic-pool": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", - "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==" - }, "glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -4972,22 +4792,6 @@ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==" }, - "language-classifier": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/language-classifier/-/language-classifier-0.0.1.tgz", - "integrity": "sha512-myU10NLx/dfATa7b0NJiycU4jlU15fMLcnfXYEO6NPMhH1vHYKMp9eoRZaQMDTu3bz25bD31Q9klsf26oOW1BQ==", - "requires": { - "classifier": "~0.1.0" - } - }, - "language-detect": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/language-detect/-/language-detect-1.1.0.tgz", - "integrity": "sha512-2kXHOATTovlwlh1LJE21DLyGiuvX6bK8CYw9kEyui2FeNBV3EYD2OE9h1ChuWNGXe/TGcm7PqpK/32S614R1Kg==", - "requires": { - "language-classifier": "0.0.1" - } - }, "lilconfig": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", @@ -5598,19 +5402,6 @@ "picomatch": "^2.2.1" } }, - "redis": { - "version": "4.6.7", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.7.tgz", - "integrity": "sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw==", - "requires": { - "@redis/bloom": "1.2.0", - "@redis/client": "1.5.8", - "@redis/graph": "1.1.0", - "@redis/json": "1.0.4", - "@redis/search": "1.1.3", - "@redis/time-series": "1.0.4" - } - }, "refractor": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", @@ -5831,11 +5622,6 @@ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true }, - "underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" - }, "unified": { "version": "10.1.2", "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", @@ -5982,11 +5768,6 @@ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", diff --git a/extension/react-app/src/components/CodeBlock.tsx b/extension/react-app/src/components/CodeBlock.tsx index 98760fbd..b0de13ac 100644 --- a/extension/react-app/src/components/CodeBlock.tsx +++ b/extension/react-app/src/components/CodeBlock.tsx @@ -61,9 +61,55 @@ function CopyButton(props: { textToCopy: string; visible: boolean }) { ); } -function CodeBlock(props: { language?: string; children: string }) { +function CodeBlock(props: { children: string }) { + const [result, setResult] = useState( + undefined + ); useEffect(() => { - hljs.highlightAll(); + const result = hljs.highlightAuto( + (props.children as any).props.children[0], + [ + "python", + "javascript", + "typescript", + "bash", + "html", + "css", + "json", + "yaml", + "markdown", + "sql", + "java", + "c", + "cpp", + "csharp", + "go", + "kotlin", + "php", + "ruby", + "rust", + "scala", + "swift", + "dart", + "haskell", + "perl", + "r", + "matlab", + "powershell", + "lua", + "elixir", + "clojure", + "groovy", + "julia", + "vbnet", + "objectivec", + "fsharp", + "erlang", + "ocaml", + ] + ); + console.log(result); + setResult(result); }, [props.children]); const [hovered, setHovered] = useState(false); @@ -82,7 +128,9 @@ function CodeBlock(props: { language?: string; children: string }) { textToCopy={(props.children as any).props.children[0]} /> - {props.children} + + {(props.children as any).props.children[0]} + ); } diff --git a/extension/react-app/src/components/StyledCode.tsx b/extension/react-app/src/components/StyledCode.tsx index 485c70b6..c5ed0101 100644 --- a/extension/react-app/src/components/StyledCode.tsx +++ b/extension/react-app/src/components/StyledCode.tsx @@ -12,7 +12,7 @@ const StyledCode = (props: StyledCodeProps) => ( style={highlightStyle} language={props.language || "python"} > - {(props.children as any).props.children} + {props.children} ); diff --git a/extension/schema/History.d.ts b/extension/schema/History.d.ts index 508deaf0..6eb8ad81 100644 --- a/extension/schema/History.d.ts +++ b/extension/schema/History.d.ts @@ -8,8 +8,19 @@ export type History = History1; export type Name = string; export type Hide = boolean; +export type Description = string; export type SystemMessage = string; +export type Role = "assistant" | "user" | "system" | "function"; +export type Content = string; +export type Name1 = string; +export type Summary = string; +export type Name2 = string; +export type Arguments = string; +export type ChatContext = ChatMessage[]; +export type ManageOwnChatContext = boolean; export type Depth = number; +export type Deleted = boolean; +export type Active = boolean; export type Timeline = HistoryNode[]; export type CurrentIndex = number; @@ -28,12 +39,30 @@ export interface HistoryNode { step: Step; observation?: Observation; depth: Depth; + deleted?: Deleted; + active?: Active; [k: string]: unknown; } export interface Step { name?: Name; hide?: Hide; + description?: Description; system_message?: SystemMessage; + chat_context?: ChatContext; + manage_own_chat_context?: ManageOwnChatContext; + [k: string]: unknown; +} +export interface ChatMessage { + role: Role; + content?: Content; + name?: Name1; + summary: Summary; + function_call?: FunctionCall; + [k: string]: unknown; +} +export interface FunctionCall { + name: Name2; + arguments: Arguments; [k: string]: unknown; } export interface Observation { diff --git a/extension/schema/HistoryNode.d.ts b/extension/schema/HistoryNode.d.ts index c1507270..bc77be89 100644 --- a/extension/schema/HistoryNode.d.ts +++ b/extension/schema/HistoryNode.d.ts @@ -8,8 +8,19 @@ export type HistoryNode = HistoryNode1; export type Name = string; export type Hide = boolean; +export type Description = string; export type SystemMessage = string; +export type Role = "assistant" | "user" | "system" | "function"; +export type Content = string; +export type Name1 = string; +export type Summary = string; +export type Name2 = string; +export type Arguments = string; +export type ChatContext = ChatMessage[]; +export type ManageOwnChatContext = boolean; export type Depth = number; +export type Deleted = boolean; +export type Active = boolean; /** * A point in history, a list of which make up History @@ -18,12 +29,30 @@ export interface HistoryNode1 { step: Step; observation?: Observation; depth: Depth; + deleted?: Deleted; + active?: Active; [k: string]: unknown; } export interface Step { name?: Name; hide?: Hide; + description?: Description; system_message?: SystemMessage; + chat_context?: ChatContext; + manage_own_chat_context?: ManageOwnChatContext; + [k: string]: unknown; +} +export interface ChatMessage { + role: Role; + content?: Content; + name?: Name1; + summary: Summary; + function_call?: FunctionCall; + [k: string]: unknown; +} +export interface FunctionCall { + name: Name2; + arguments: Arguments; [k: string]: unknown; } export interface Observation { diff --git a/schema/json/History.json b/schema/json/History.json index 14b82d6d..ee797412 100644 --- a/schema/json/History.json +++ b/schema/json/History.json @@ -2,6 +2,59 @@ "title": "History", "$ref": "#/definitions/src__continuedev__core__main__History", "definitions": { + "FunctionCall": { + "title": "FunctionCall", + "type": "object", + "properties": { + "name": { + "title": "Name", + "type": "string" + }, + "arguments": { + "title": "Arguments", + "type": "string" + } + }, + "required": [ + "name", + "arguments" + ] + }, + "ChatMessage": { + "title": "ChatMessage", + "type": "object", + "properties": { + "role": { + "title": "Role", + "enum": [ + "assistant", + "user", + "system", + "function" + ], + "type": "string" + }, + "content": { + "title": "Content", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + }, + "summary": { + "title": "Summary", + "type": "string" + }, + "function_call": { + "$ref": "#/definitions/FunctionCall" + } + }, + "required": [ + "role", + "summary" + ] + }, "Step": { "title": "Step", "type": "object", @@ -15,9 +68,26 @@ "default": false, "type": "boolean" }, + "description": { + "title": "Description", + "type": "string" + }, "system_message": { "title": "System Message", "type": "string" + }, + "chat_context": { + "title": "Chat Context", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/ChatMessage" + } + }, + "manage_own_chat_context": { + "title": "Manage Own Chat Context", + "default": false, + "type": "boolean" } } }, @@ -40,6 +110,16 @@ "depth": { "title": "Depth", "type": "integer" + }, + "deleted": { + "title": "Deleted", + "default": false, + "type": "boolean" + }, + "active": { + "title": "Active", + "default": true, + "type": "boolean" } }, "required": [ diff --git a/schema/json/HistoryNode.json b/schema/json/HistoryNode.json index 87a8729f..d0e12ac5 100644 --- a/schema/json/HistoryNode.json +++ b/schema/json/HistoryNode.json @@ -2,6 +2,59 @@ "title": "HistoryNode", "$ref": "#/definitions/src__continuedev__core__main__HistoryNode", "definitions": { + "FunctionCall": { + "title": "FunctionCall", + "type": "object", + "properties": { + "name": { + "title": "Name", + "type": "string" + }, + "arguments": { + "title": "Arguments", + "type": "string" + } + }, + "required": [ + "name", + "arguments" + ] + }, + "ChatMessage": { + "title": "ChatMessage", + "type": "object", + "properties": { + "role": { + "title": "Role", + "enum": [ + "assistant", + "user", + "system", + "function" + ], + "type": "string" + }, + "content": { + "title": "Content", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + }, + "summary": { + "title": "Summary", + "type": "string" + }, + "function_call": { + "$ref": "#/definitions/FunctionCall" + } + }, + "required": [ + "role", + "summary" + ] + }, "Step": { "title": "Step", "type": "object", @@ -15,9 +68,26 @@ "default": false, "type": "boolean" }, + "description": { + "title": "Description", + "type": "string" + }, "system_message": { "title": "System Message", "type": "string" + }, + "chat_context": { + "title": "Chat Context", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/ChatMessage" + } + }, + "manage_own_chat_context": { + "title": "Manage Own Chat Context", + "default": false, + "type": "boolean" } } }, @@ -40,6 +110,16 @@ "depth": { "title": "Depth", "type": "integer" + }, + "deleted": { + "title": "Deleted", + "default": false, + "type": "boolean" + }, + "active": { + "title": "Active", + "default": true, + "type": "boolean" } }, "required": [ -- cgit v1.2.3-70-g09d2 From 5c03dd4775845c559a1f6298f7577609ba907bb1 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Wed, 5 Jul 2023 23:49:37 -0700 Subject: ui overhaul --- continuedev/src/continuedev/core/autopilot.py | 47 +++- continuedev/src/continuedev/core/main.py | 9 +- .../src/continuedev/models/generate_json_schema.py | 4 +- continuedev/src/continuedev/server/gui.py | 14 + .../media/Lexend/Lexend-VariableFont_wght.ttf | Bin 0 -> 176220 bytes extension/media/Lexend/OFL.txt | 93 +++++++ extension/media/Lexend/README.txt | 71 +++++ extension/media/Lexend/static/Lexend-Black.ttf | Bin 0 -> 78496 bytes extension/media/Lexend/static/Lexend-Bold.ttf | Bin 0 -> 78632 bytes extension/media/Lexend/static/Lexend-ExtraBold.ttf | Bin 0 -> 78716 bytes .../media/Lexend/static/Lexend-ExtraLight.ttf | Bin 0 -> 78508 bytes extension/media/Lexend/static/Lexend-Light.ttf | Bin 0 -> 78668 bytes extension/media/Lexend/static/Lexend-Medium.ttf | Bin 0 -> 78696 bytes extension/media/Lexend/static/Lexend-Regular.ttf | Bin 0 -> 78360 bytes extension/media/Lexend/static/Lexend-SemiBold.ttf | Bin 0 -> 78744 bytes extension/media/Lexend/static/Lexend-Thin.ttf | Bin 0 -> 78380 bytes extension/react-app/package-lock.json | 59 ++++ extension/react-app/package.json | 1 + extension/react-app/src/App.tsx | 39 +-- extension/react-app/src/components/CodeBlock.tsx | 4 +- extension/react-app/src/components/ComboBox.tsx | 191 +++++++------ .../react-app/src/components/ContinueButton.tsx | 2 +- .../src/components/HeaderButtonWithText.tsx | 44 +-- extension/react-app/src/components/Loader.tsx | 40 +++ extension/react-app/src/components/PillButton.tsx | 144 +++++++--- .../react-app/src/components/StepContainer.tsx | 13 +- extension/react-app/src/components/TextDialog.tsx | 2 +- .../src/components/UserInputContainer.tsx | 6 +- extension/react-app/src/components/index.ts | 22 +- .../src/hooks/ContinueGUIClientProtocol.ts | 4 + .../react-app/src/hooks/useContinueGUIProtocol.ts | 8 + extension/react-app/src/index.css | 9 +- extension/react-app/src/main.tsx | 6 +- extension/react-app/src/tabs/gui.tsx | 22 +- extension/schema/FullState.d.ts | 133 +++++++++ extension/src/debugPanel.ts | 4 + schema/json/FullState.json | 304 +++++++++++++++++++++ 37 files changed, 1088 insertions(+), 207 deletions(-) create mode 100644 extension/media/Lexend/Lexend-VariableFont_wght.ttf create mode 100644 extension/media/Lexend/OFL.txt create mode 100644 extension/media/Lexend/README.txt create mode 100644 extension/media/Lexend/static/Lexend-Black.ttf create mode 100644 extension/media/Lexend/static/Lexend-Bold.ttf create mode 100644 extension/media/Lexend/static/Lexend-ExtraBold.ttf create mode 100644 extension/media/Lexend/static/Lexend-ExtraLight.ttf create mode 100644 extension/media/Lexend/static/Lexend-Light.ttf create mode 100644 extension/media/Lexend/static/Lexend-Medium.ttf create mode 100644 extension/media/Lexend/static/Lexend-Regular.ttf create mode 100644 extension/media/Lexend/static/Lexend-SemiBold.ttf create mode 100644 extension/media/Lexend/static/Lexend-Thin.ttf create mode 100644 extension/react-app/src/components/Loader.tsx create mode 100644 extension/schema/FullState.d.ts create mode 100644 schema/json/FullState.json (limited to 'extension/schema') diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py index b1c4f471..acdc1f0d 100644 --- a/continuedev/src/continuedev/core/autopilot.py +++ b/continuedev/src/continuedev/core/autopilot.py @@ -12,7 +12,7 @@ from .observation import Observation, InternalErrorObservation from ..server.ide_protocol import AbstractIdeProtocolServer from ..libs.util.queue import AsyncSubscriptionQueue from ..models.main import ContinueBaseModel -from .main import Context, ContinueCustomException, Policy, History, FullState, Step, HistoryNode +from .main import Context, ContinueCustomException, HighlightedRangeContext, Policy, History, FullState, Step, HistoryNode from ..steps.core.core import ReversibleStep, ManualEditStep, UserInputStep from ..libs.util.telemetry import capture_event from .sdk import ContinueSDK @@ -140,11 +140,24 @@ class Autopilot(ContinueBaseModel): tb_step.step_name, {"output": output, **tb_step.params}) await self._run_singular_step(step) - _highlighted_ranges: List[RangeInFileWithContents] = [] + _highlighted_ranges: List[HighlightedRangeContext] = [] _adding_highlighted_code: bool = False + def _make_sure_is_editing_range(self): + """If none of the highlighted ranges are currently being edited, the first should be selected""" + if len(self._highlighted_ranges) == 0: + return + if not any(map(lambda x: x.editing, self._highlighted_ranges)): + self._highlighted_ranges[0].editing = True + async def handle_highlighted_code(self, range_in_files: List[RangeInFileWithContents]): - if not self._adding_highlighted_code: + if not self._adding_highlighted_code and len(self._highlighted_ranges) > 0: + return + + # If un-highlighting, then remove the range + if len(self._highlighted_ranges) == 1 and len(range_in_files) == 1 and range_in_files[0].range.start == range_in_files[0].range.end: + self._highlighted_ranges = [] + await self.update_subscribers() return # Filter out rifs from ~/.continue/diffs folder @@ -160,20 +173,25 @@ class Autopilot(ContinueBaseModel): for i, rif in enumerate(self._highlighted_ranges): found_overlap = False for new_rif in range_in_files: - if rif.filepath == new_rif.filepath and rif.range.overlaps_with(new_rif.range): + if rif.range.filepath == new_rif.filepath and rif.range.range.overlaps_with(new_rif.range): found_overlap = True break # Also don't allow multiple ranges in same file with same content. This is useless to the model, and avoids # the bug where cmd+f causes repeated highlights - if rif.filepath == new_rif.filepath and rif.contents == new_rif.contents: + if rif.range.filepath == new_rif.filepath and rif.range.contents == new_rif.contents: found_overlap = True break if not found_overlap: new_ranges.append(rif) - self._highlighted_ranges = new_ranges + range_in_files + self._highlighted_ranges = new_ranges + [HighlightedRangeContext( + range=rif, editing=False, pinned=False + ) for rif in range_in_files] + + self._make_sure_is_editing_range() + await self.update_subscribers() _step_depth: int = 0 @@ -193,12 +211,25 @@ class Autopilot(ContinueBaseModel): if i not in indices: kept_ranges.append(rif) self._highlighted_ranges = kept_ranges + + self._make_sure_is_editing_range() + await self.update_subscribers() async def toggle_adding_highlighted_code(self): self._adding_highlighted_code = not self._adding_highlighted_code await self.update_subscribers() + async def set_editing_at_indices(self, indices: List[int]): + for i in range(len(self._highlighted_ranges)): + self._highlighted_ranges[i].editing = i in indices + await self.update_subscribers() + + async def set_pinned_at_indices(self, indices: List[int]): + for i in range(len(self._highlighted_ranges)): + self._highlighted_ranges[i].pinned = i in indices + await self.update_subscribers() + async def _run_singular_step(self, step: "Step", is_future_step: bool = False) -> Coroutine[Observation, None, None]: # Allow config to set disallowed steps if step.__class__.__name__ in self.continue_sdk.config.disallowed_steps: @@ -359,6 +390,10 @@ class Autopilot(ContinueBaseModel): if len(self._main_user_input_queue) > 1: return + # Remove context unless pinned + self._highlighted_ranges = [ + hr for hr in self._highlighted_ranges if hr.pinned] + # await self._request_halt() # Just run the step that takes user input, and # then up to the policy to decide how to deal with it. diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py index 28fd964e..62cc4936 100644 --- a/continuedev/src/continuedev/core/main.py +++ b/continuedev/src/continuedev/core/main.py @@ -199,13 +199,20 @@ class SlashCommandDescription(ContinueBaseModel): description: str +class HighlightedRangeContext(ContinueBaseModel): + """Context for a highlighted range""" + range: RangeInFileWithContents + editing: bool + pinned: bool + + class FullState(ContinueBaseModel): """A full state of the program, including the history""" history: History active: bool user_input_queue: List[str] default_model: str - highlighted_ranges: List[RangeInFileWithContents] + highlighted_ranges: List[HighlightedRangeContext] slash_commands: List[SlashCommandDescription] adding_highlighted_code: bool diff --git a/continuedev/src/continuedev/models/generate_json_schema.py b/continuedev/src/continuedev/models/generate_json_schema.py index 080787a5..6cebf429 100644 --- a/continuedev/src/continuedev/models/generate_json_schema.py +++ b/continuedev/src/continuedev/models/generate_json_schema.py @@ -1,7 +1,7 @@ from .main import * from .filesystem import RangeInFile, FileEdit from .filesystem_edit import FileEditWithFullContents -from ..core.main import History, HistoryNode +from ..core.main import History, HistoryNode, FullState from pydantic import schema_json_of import os @@ -12,7 +12,7 @@ MODELS_TO_GENERATE = [ ] + [ FileEditWithFullContents ] + [ - History, HistoryNode + History, HistoryNode, FullState ] RENAMES = { diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py index fa573b37..8e9b1fb9 100644 --- a/continuedev/src/continuedev/server/gui.py +++ b/continuedev/src/continuedev/server/gui.py @@ -87,6 +87,10 @@ class GUIProtocolServer(AbstractGUIProtocolServer): self.on_delete_context_at_indices(data["indices"]) elif message_type == "toggle_adding_highlighted_code": self.on_toggle_adding_highlighted_code() + elif message_type == "set_editing_at_indices": + self.on_set_editing_at_indices(data["indices"]) + elif message_type == "set_pinned_at_indices": + self.on_set_pinned_at_indices(data["indices"]) except Exception as e: print(e) @@ -135,6 +139,16 @@ class GUIProtocolServer(AbstractGUIProtocolServer): self.session.autopilot.toggle_adding_highlighted_code() ) + def on_set_editing_at_indices(self, indices: List[int]): + asyncio.create_task( + self.session.autopilot.set_editing_at_indices(indices) + ) + + def on_set_pinned_at_indices(self, indices: List[int]): + asyncio.create_task( + self.session.autopilot.set_pinned_at_indices(indices) + ) + @router.websocket("/ws") async def websocket_endpoint(websocket: WebSocket, session: Session = Depends(websocket_session)): diff --git a/extension/media/Lexend/Lexend-VariableFont_wght.ttf b/extension/media/Lexend/Lexend-VariableFont_wght.ttf new file mode 100644 index 00000000..b294dc84 Binary files /dev/null and b/extension/media/Lexend/Lexend-VariableFont_wght.ttf differ diff --git a/extension/media/Lexend/OFL.txt b/extension/media/Lexend/OFL.txt new file mode 100644 index 00000000..6b679248 --- /dev/null +++ b/extension/media/Lexend/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2018 The Lexend Project Authors (https://github.com/googlefonts/lexend), with Reserved Font Name “RevReading Lexend”. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/extension/media/Lexend/README.txt b/extension/media/Lexend/README.txt new file mode 100644 index 00000000..f2966dfe --- /dev/null +++ b/extension/media/Lexend/README.txt @@ -0,0 +1,71 @@ +Lexend Variable Font +==================== + +This download contains Lexend as both a variable font and static fonts. + +Lexend is a variable font with this axis: + wght + +This means all the styles are contained in a single file: + Lexend-VariableFont_wght.ttf + +If your app fully supports variable fonts, you can now pick intermediate styles +that aren’t available as static fonts. Not all apps support variable fonts, and +in those cases you can use the static font files for Lexend: + static/Lexend-Thin.ttf + static/Lexend-ExtraLight.ttf + static/Lexend-Light.ttf + static/Lexend-Regular.ttf + static/Lexend-Medium.ttf + static/Lexend-SemiBold.ttf + static/Lexend-Bold.ttf + static/Lexend-ExtraBold.ttf + static/Lexend-Black.ttf + +Get started +----------- + +1. Install the font files you want to use + +2. Use your app's font picker to view the font family and all the +available styles + +Learn more about variable fonts +------------------------------- + + https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts + https://variablefonts.typenetwork.com + https://medium.com/variable-fonts + +In desktop apps + + https://theblog.adobe.com/can-variable-fonts-illustrator-cc + https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts + +Online + + https://developers.google.com/fonts/docs/getting_started + https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide + https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts + +Installing fonts + + MacOS: https://support.apple.com/en-us/HT201749 + Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux + Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows + +Android Apps + + https://developers.google.com/fonts/docs/android + https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts + +License +------- +Please read the full license text (OFL.txt) to understand the permissions, +restrictions and requirements for usage, redistribution, and modification. + +You can use them in your products & projects – print or digital, +commercial or otherwise. + +This isn't legal advice, please consider consulting a lawyer and see the full +license for all details. diff --git a/extension/media/Lexend/static/Lexend-Black.ttf b/extension/media/Lexend/static/Lexend-Black.ttf new file mode 100644 index 00000000..2fea087c Binary files /dev/null and b/extension/media/Lexend/static/Lexend-Black.ttf differ diff --git a/extension/media/Lexend/static/Lexend-Bold.ttf b/extension/media/Lexend/static/Lexend-Bold.ttf new file mode 100644 index 00000000..95884f6e Binary files /dev/null and b/extension/media/Lexend/static/Lexend-Bold.ttf differ diff --git a/extension/media/Lexend/static/Lexend-ExtraBold.ttf b/extension/media/Lexend/static/Lexend-ExtraBold.ttf new file mode 100644 index 00000000..02f84ed3 Binary files /dev/null and b/extension/media/Lexend/static/Lexend-ExtraBold.ttf differ diff --git a/extension/media/Lexend/static/Lexend-ExtraLight.ttf b/extension/media/Lexend/static/Lexend-ExtraLight.ttf new file mode 100644 index 00000000..20e7068d Binary files /dev/null and b/extension/media/Lexend/static/Lexend-ExtraLight.ttf differ diff --git a/extension/media/Lexend/static/Lexend-Light.ttf b/extension/media/Lexend/static/Lexend-Light.ttf new file mode 100644 index 00000000..fb6d097c Binary files /dev/null and b/extension/media/Lexend/static/Lexend-Light.ttf differ diff --git a/extension/media/Lexend/static/Lexend-Medium.ttf b/extension/media/Lexend/static/Lexend-Medium.ttf new file mode 100644 index 00000000..d91a8673 Binary files /dev/null and b/extension/media/Lexend/static/Lexend-Medium.ttf differ diff --git a/extension/media/Lexend/static/Lexend-Regular.ttf b/extension/media/Lexend/static/Lexend-Regular.ttf new file mode 100644 index 00000000..b423d3ab Binary files /dev/null and b/extension/media/Lexend/static/Lexend-Regular.ttf differ diff --git a/extension/media/Lexend/static/Lexend-SemiBold.ttf b/extension/media/Lexend/static/Lexend-SemiBold.ttf new file mode 100644 index 00000000..9dcb8214 Binary files /dev/null and b/extension/media/Lexend/static/Lexend-SemiBold.ttf differ diff --git a/extension/media/Lexend/static/Lexend-Thin.ttf b/extension/media/Lexend/static/Lexend-Thin.ttf new file mode 100644 index 00000000..0d7df881 Binary files /dev/null and b/extension/media/Lexend/static/Lexend-Thin.ttf differ diff --git a/extension/react-app/package-lock.json b/extension/react-app/package-lock.json index fb13dffd..7316581d 100644 --- a/extension/react-app/package-lock.json +++ b/extension/react-app/package-lock.json @@ -20,6 +20,7 @@ "react-redux": "^8.0.5", "react-switch": "^7.0.0", "react-syntax-highlighter": "^15.5.0", + "react-tooltip": "^5.18.0", "styled-components": "^5.3.6", "vscode-webview": "^1.0.1-beta.1" }, @@ -597,6 +598,19 @@ "node": ">=12" } }, + "node_modules/@floating-ui/core": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.3.1.tgz", + "integrity": "sha512-Bu+AMaXNjrpjh41znzHqaz3r2Nr8hHuHZT6V2LBKMhyMl0FgKA62PNYbqnfgmzOhoWZj70Zecisbo4H1rotP5g==" + }, + "node_modules/@floating-ui/dom": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.4.4.tgz", + "integrity": "sha512-21hhDEPOiWkGp0Ys4Wi6Neriah7HweToKra626CIK712B5m9qkdz54OP9gVldUg+URnBTpv/j/bi/skmGdstXQ==", + "dependencies": { + "@floating-ui/core": "^1.3.1" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -1310,6 +1324,11 @@ "node": ">= 6" } }, + "node_modules/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -2967,6 +2986,19 @@ "react": ">= 0.14.0" } }, + "node_modules/react-tooltip": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.18.0.tgz", + "integrity": "sha512-qjDK/skUJJ27sc9lTWeNxp2rLzmenBTskSsRiDOCPnupGSz2GhL5IZxDizK/sOsk0hn5iSCywt+3jKxUJ3Y4Sw==", + "dependencies": { + "@floating-ui/dom": "^1.0.0", + "classnames": "^2.3.0" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -3886,6 +3918,19 @@ "dev": true, "optional": true }, + "@floating-ui/core": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.3.1.tgz", + "integrity": "sha512-Bu+AMaXNjrpjh41znzHqaz3r2Nr8hHuHZT6V2LBKMhyMl0FgKA62PNYbqnfgmzOhoWZj70Zecisbo4H1rotP5g==" + }, + "@floating-ui/dom": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.4.4.tgz", + "integrity": "sha512-21hhDEPOiWkGp0Ys4Wi6Neriah7HweToKra626CIK712B5m9qkdz54OP9gVldUg+URnBTpv/j/bi/skmGdstXQ==", + "requires": { + "@floating-ui/core": "^1.3.1" + } + }, "@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -4350,6 +4395,11 @@ } } }, + "classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -5411,6 +5461,15 @@ "refractor": "^3.6.0" } }, + "react-tooltip": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.18.0.tgz", + "integrity": "sha512-qjDK/skUJJ27sc9lTWeNxp2rLzmenBTskSsRiDOCPnupGSz2GhL5IZxDizK/sOsk0hn5iSCywt+3jKxUJ3Y4Sw==", + "requires": { + "@floating-ui/dom": "^1.0.0", + "classnames": "^2.3.0" + } + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", diff --git a/extension/react-app/package.json b/extension/react-app/package.json index 12701906..4bedb813 100644 --- a/extension/react-app/package.json +++ b/extension/react-app/package.json @@ -21,6 +21,7 @@ "react-redux": "^8.0.5", "react-switch": "^7.0.0", "react-syntax-highlighter": "^15.5.0", + "react-tooltip": "^5.18.0", "styled-components": "^5.3.6", "vscode-webview": "^1.0.1-beta.1" }, diff --git a/extension/react-app/src/App.tsx b/extension/react-app/src/App.tsx index a51541d0..8785f88f 100644 --- a/extension/react-app/src/App.tsx +++ b/extension/react-app/src/App.tsx @@ -1,28 +1,33 @@ import DebugPanel from "./components/DebugPanel"; import MainTab from "./tabs/main"; -import { Provider } from "react-redux"; -import store from "./redux/store"; import WelcomeTab from "./tabs/welcome"; import ChatTab from "./tabs/chat"; import GUI from "./tabs/gui"; +import { createContext } from "react"; +import useContinueGUIProtocol from "./hooks/useWebsocket"; +import ContinueGUIClientProtocol from "./hooks/useContinueGUIProtocol"; + +export const GUIClientContext = createContext< + ContinueGUIClientProtocol | undefined +>(undefined); function App() { + const client = useContinueGUIProtocol(); + return ( - <> - - , - title: "GUI", - }, - // { element: , title: "Debug Panel" }, - // { element: , title: "Welcome" }, - // { element: , title: "Chat" }, - ]} - > - - + + , + title: "GUI", + }, + // { element: , title: "Debug Panel" }, + // { element: , title: "Welcome" }, + // { element: , title: "Chat" }, + ]} + /> + ); } diff --git a/extension/react-app/src/components/CodeBlock.tsx b/extension/react-app/src/components/CodeBlock.tsx index 17f5626b..fe9b3a95 100644 --- a/extension/react-app/src/components/CodeBlock.tsx +++ b/extension/react-app/src/components/CodeBlock.tsx @@ -52,9 +52,9 @@ function CopyButton(props: { textToCopy: string; visible: boolean }) { }} > {clicked ? ( - + ) : ( - + )} diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx index 81b148b9..7ee5dc24 100644 --- a/extension/react-app/src/components/ComboBox.tsx +++ b/extension/react-app/src/components/ComboBox.tsx @@ -4,6 +4,7 @@ import styled from "styled-components"; import { buttonColor, defaultBorderRadius, + lightGray, secondaryDark, vscBackground, } from "."; @@ -16,11 +17,32 @@ import { LockClosed, LockOpen, Plus, + DocumentPlus, } from "@styled-icons/heroicons-outline"; +import { HighlightedRangeContext } from "../../../schema/FullState"; // #region styled components const mainInputFontSize = 16; +const EmptyPillDiv = styled.div` + padding: 8px; + border-radius: ${defaultBorderRadius}; + border: 1px dashed ${lightGray}; + color: ${lightGray}; + background-color: ${vscBackground}; + overflow: hidden; + display: flex; + align-items: center; + text-align: center; + cursor: pointer; + font-size: 13px; + + &:hover { + background-color: ${lightGray}; + color: ${vscBackground}; + } +`; + const ContextDropdown = styled.div` position: absolute; padding: 4px; @@ -41,17 +63,19 @@ const MainTextInput = styled.textarea` padding: 8px; font-size: ${mainInputFontSize}px; + font-family: inherit; + border: 1px solid transparent; border-radius: ${defaultBorderRadius}; - border: 1px solid white; margin: 8px auto; + height: auto; width: 100%; - background-color: ${vscBackground}; + background-color: ${secondaryDark}; color: white; z-index: 1; &:focus { + outline: 1px solid #ff000066; border: 1px solid transparent; - outline: 1px solid orange; } `; @@ -69,7 +93,6 @@ const Ul = styled.ul<{ background: ${vscBackground}; background-color: ${secondaryDark}; color: white; - font-family: "Fira Code", monospace; max-height: ${UlMaxHeight}px; overflow: scroll; padding: 0; @@ -102,7 +125,7 @@ interface ComboBoxProps { onInputValueChange: (inputValue: string) => void; disabled?: boolean; onEnter: (e: React.KeyboardEvent) => void; - highlightedCodeSections: (RangeInFile & { contents: string })[]; + highlightedCodeSections: HighlightedRangeContext[]; deleteContextItems: (indices: number[]) => void; onTogglePin: () => void; onToggleAddContext: () => void; @@ -119,16 +142,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { React.useState(false); const [pinned, setPinned] = useState(false); const [highlightedCodeSections, setHighlightedCodeSections] = React.useState( - props.highlightedCodeSections || [ - { - filepath: "test.ts", - range: { - start: { line: 0, character: 0 }, - end: { line: 0, character: 0 }, - }, - contents: "import * as a from 'a';", - }, - ] + props.highlightedCodeSections || [] ); useEffect(() => { @@ -169,6 +183,71 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { return ( <> +
+ {highlightedCodeSections.length > 1 && ( + <> + { + props.deleteContextItems( + highlightedCodeSections.map((_, idx) => idx) + ); + }} + > + + + + )} + {highlightedCodeSections.map((section, idx) => ( + { + if (props.deleteContextItems) { + props.deleteContextItems([idx]); + } + setHighlightedCodeSections((prev) => { + const newSections = [...prev]; + newSections.splice(idx, 1); + return newSections; + }); + }} + onHover={(val: boolean) => { + if (val) { + setHoveringButton(val); + } else { + setTimeout(() => { + setHoveringButton(val); + }, 100); + } + }} + /> + ))} + {props.highlightedCodeSections.length > 0 && + (props.addingHighlightedCode ? ( + { + props.onToggleAddContext(); + }} + > + Highlight to Add Context + + ) : ( + { + props.onToggleAddContext(); + }} + > + + + ))} +
-
- {highlightedCodeSections.length === 0 && ( - { - props.onToggleAddContext(); - }} - inverted={props.addingHighlightedCode} - > - - - )} - {highlightedCodeSections.length > 0 && ( - <> - { - props.deleteContextItems( - highlightedCodeSections.map((_, idx) => idx) - ); - }} - > - - - { - setPinned((prev) => !prev); - props.onTogglePin(); - }} - > - {pinned ? ( - - ) : ( - - )} - - - )} - {highlightedCodeSections.map((section, idx) => ( - { - if (props.deleteContextItems) { - props.deleteContextItems([idx]); - } - setHighlightedCodeSections((prev) => { - const newSections = [...prev]; - newSections.splice(idx, 1); - return newSections; - }); - }} - onHover={(val: boolean) => { - if (val) { - setHoveringButton(val); - } else { - setTimeout(() => { - setHoveringButton(val); - }, 100); - } - }} - /> - ))} - - - Highlight code to include as context. Currently open file included by - default. {highlightedCodeSections.length === 0 && ""} - -
+ {/* + Highlight code to include as context. Currently open file included by + default. {highlightedCodeSections.length === 0 && ""} + */} { setHoveringContextDropdown(true); @@ -345,9 +354,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { > {highlightedCodeSections.map((section, idx) => ( <> -

{section.filepath}

+

{section.range.filepath}

- {section.contents} + {section.range.contents} ))} diff --git a/extension/react-app/src/components/ContinueButton.tsx b/extension/react-app/src/components/ContinueButton.tsx index 5295799a..462f2b46 100644 --- a/extension/react-app/src/components/ContinueButton.tsx +++ b/extension/react-app/src/components/ContinueButton.tsx @@ -18,7 +18,7 @@ let StyledButton = styled(Button)` &:hover { transition-delay: 0.5s; - transition-property: background; + transition-property: "background"; background: linear-gradient( 45deg, #be1a55 14.44%, diff --git a/extension/react-app/src/components/HeaderButtonWithText.tsx b/extension/react-app/src/components/HeaderButtonWithText.tsx index 72a653c5..de8e3c98 100644 --- a/extension/react-app/src/components/HeaderButtonWithText.tsx +++ b/extension/react-app/src/components/HeaderButtonWithText.tsx @@ -1,6 +1,7 @@ import React, { useState } from "react"; - -import { HeaderButton } from "."; +import { Tooltip } from "react-tooltip"; +import styled from "styled-components"; +import { HeaderButton, StyledTooltip, defaultBorderRadius } from "."; interface HeaderButtonWithTextProps { text: string; @@ -13,25 +14,28 @@ interface HeaderButtonWithTextProps { const HeaderButtonWithText = (props: HeaderButtonWithTextProps) => { const [hover, setHover] = useState(false); - const paddingLeft = (props.disabled ? (props.active ? "3px" : "1px"): (hover ? "4px" : "1px")); return ( - { - if (!props.disabled) { - setHover(true); - } - }} - onMouseLeave={() => { - setHover(false); - }} - onClick={props.onClick} - > - - {props.children} - + <> + { + if (!props.disabled) { + setHover(true); + } + }} + onMouseLeave={() => { + setHover(false); + }} + onClick={props.onClick} + > + {props.children} + + + {props.text} + + ); }; diff --git a/extension/react-app/src/components/Loader.tsx b/extension/react-app/src/components/Loader.tsx new file mode 100644 index 00000000..90eff793 --- /dev/null +++ b/extension/react-app/src/components/Loader.tsx @@ -0,0 +1,40 @@ +import { Play } from "@styled-icons/heroicons-outline"; +import { useSelector } from "react-redux"; +import styled from "styled-components"; +import { RootStore } from "../redux/store"; + +const DEFAULT_SIZE = "28px"; + +const FlashingDiv = styled.div` + margin: auto; + width: ${DEFAULT_SIZE}; + animation: flash 1.2s infinite ease-in-out; + @keyframes flash { + 0% { + opacity: 0.4; + } + 50% { + opacity: 1; + } + 100% { + opacity: 0.4; + } + } +`; + +function Loader(props: { size?: string }) { + const vscMediaUrl = useSelector( + (state: RootStore) => state.config.vscMediaUrl + ); + return ( + + {vscMediaUrl ? ( + + ) : ( + + )} + + ); +} + +export default Loader; diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx index 5a02c6b2..a384832e 100644 --- a/extension/react-app/src/components/PillButton.tsx +++ b/extension/react-app/src/components/PillButton.tsx @@ -1,54 +1,136 @@ -import { useState } from "react"; +import { useContext, useState } from "react"; import styled from "styled-components"; -import { defaultBorderRadius } from "."; -import { XMark } from "@styled-icons/heroicons-outline"; +import { + StyledTooltip, + defaultBorderRadius, + lightGray, + secondaryDark, +} from "."; +import { Trash, PaintBrush, MapPin } from "@styled-icons/heroicons-outline"; +import { GUIClientContext } from "../App"; const Button = styled.button` border: none; color: white; - background-color: transparent; - border: 1px solid white; + background-color: ${secondaryDark}; border-radius: ${defaultBorderRadius}; - padding: 3px 6px; + padding: 8px; + overflow: hidden; + + cursor: pointer; +`; + +const GridDiv = styled.div` + position: absolute; + left: 0px; + top: 0px; + width: 100%; + height: 100%; + display: grid; + grid-gap: 0; + grid-template-columns: 1fr 1fr; + align-items: center; + border-radius: ${defaultBorderRadius}; + overflow: hidden; + + background-color: ${secondaryDark}; +`; + +const ButtonDiv = styled.div<{ backgroundColor: string }>` + background-color: ${secondaryDark}; + padding: 3px; + height: 100%; + display: flex; + align-items: center; &:hover { - background-color: white; - color: black; + background-color: ${(props) => props.backgroundColor}; } - - cursor: pointer; `; interface PillButtonProps { onHover?: (arg0: boolean) => void; onDelete?: () => void; title: string; + index: number; + editing: boolean; + pinned: boolean; } const PillButton = (props: PillButtonProps) => { const [isHovered, setIsHovered] = useState(false); + const client = useContext(GUIClientContext); + return ( - + <> + + + {props.editing ? "Editing this range" : "Edit this range"} + + Delete + ); }; diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx index 2aed2e72..91d7b8ef 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -13,7 +13,7 @@ import { ArrowPath, XMark, } from "@styled-icons/heroicons-outline"; -import { Stop } from "@styled-icons/heroicons-solid"; +import { StopCircle } from "@styled-icons/heroicons-solid"; import { HistoryNode } from "../../../schema/HistoryNode"; import ReactMarkdown from "react-markdown"; import HeaderButtonWithText from "./HeaderButtonWithText"; @@ -67,7 +67,6 @@ const HeaderDiv = styled.div<{ error: boolean; loading: boolean }>` const ContentDiv = styled.div<{ isUserInput: boolean }>` padding: 8px; - padding-left: 16px; background-color: ${(props) => props.isUserInput ? secondaryDark : vscBackground}; font-size: 13px; @@ -167,7 +166,7 @@ function StepContainer(props: StepContainerProps) { ? "#f00" : props.historyNode.active ? undefined - : "white" + : "transparent" } className="overflow-hidden cursor-pointer" onClick={(e) => { @@ -182,7 +181,7 @@ function StepContainer(props: StepContainerProps) { loading={props.historyNode.active as boolean | false} error={props.historyNode.observation?.error ? true : false} > -

+
{!isUserInput && (props.open ? ( @@ -191,7 +190,7 @@ function StepContainer(props: StepContainerProps) { ))} {props.historyNode.observation?.title || (props.historyNode.step.name as any)} -

+ {/* { e.stopPropagation(); @@ -203,16 +202,14 @@ function StepContainer(props: StepContainerProps) { <> { e.stopPropagation(); props.onDelete(); }} text={props.historyNode.active ? "Stop" : "Delete"} - active={props.historyNode.active} > {props.historyNode.active ? ( - + ) : ( )} diff --git a/extension/react-app/src/components/TextDialog.tsx b/extension/react-app/src/components/TextDialog.tsx index a564f884..ea5727f0 100644 --- a/extension/react-app/src/components/TextDialog.tsx +++ b/extension/react-app/src/components/TextDialog.tsx @@ -8,6 +8,7 @@ const ScreenCover = styled.div` width: 100%; height: 100%; background-color: rgba(168, 168, 168, 0.5); + z-index: 100; `; const DialogContainer = styled.div` @@ -35,7 +36,6 @@ const TextArea = styled.textarea` border-radius: 8px; padding: 8px; outline: 1px solid black; - font-family: Arial, Helvetica, sans-serif; resize: none; &:focus { diff --git a/extension/react-app/src/components/UserInputContainer.tsx b/extension/react-app/src/components/UserInputContainer.tsx index 28437d35..f51f0cb5 100644 --- a/extension/react-app/src/components/UserInputContainer.tsx +++ b/extension/react-app/src/components/UserInputContainer.tsx @@ -15,12 +15,10 @@ interface UserInputContainerProps { } const StyledDiv = styled.div` - background-color: rgb(45 45 45); + background-color: ${secondaryDark}; padding: 8px; padding-left: 16px; padding-right: 16px; - border-bottom: 1px solid white; - border-top: 1px solid white; font-size: 13px; display: flex; align-items: center; @@ -29,7 +27,7 @@ const StyledDiv = styled.div` const UserInputContainer = (props: UserInputContainerProps) => { return ( - {props.children} + {props.children}
{ diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts index db1925ed..9ae0f097 100644 --- a/extension/react-app/src/components/index.ts +++ b/extension/react-app/src/components/index.ts @@ -1,7 +1,9 @@ +import { Tooltip } from "react-tooltip"; import styled, { keyframes } from "styled-components"; export const defaultBorderRadius = "5px"; -export const secondaryDark = "rgb(42 42 42)"; +export const lightGray = "rgb(100 100 100)"; +export const secondaryDark = "rgb(45 45 45)"; export const vscBackground = "rgb(30 30 30)"; export const vscBackgroundTransparent = "#1e1e1ede"; export const buttonColor = "rgb(113 28 59)"; @@ -26,6 +28,16 @@ export const Button = styled.button` } `; +export const StyledTooltip = styled(Tooltip)` + font-size: 12px; + background-color: rgb(60 60 60); + border-radius: ${defaultBorderRadius}; + padding: 6px; + padding-left: 12px; + padding-right: 12px; + z-index: 100; +`; + export const TextArea = styled.textarea` width: 100%; border-radius: ${defaultBorderRadius}; @@ -128,19 +140,17 @@ export const HeaderButton = styled.button<{ inverted: boolean | undefined }>` background-color: ${({ inverted }) => (inverted ? "white" : "transparent")}; color: ${({ inverted }) => (inverted ? "black" : "white")}; - border: 1px solid white; + border: none; border-radius: ${defaultBorderRadius}; cursor: pointer; &:hover { background-color: ${({ inverted }) => - typeof inverted === "undefined" || inverted ? "white" : "transparent"}; - color: ${({ inverted }) => - typeof inverted === "undefined" || inverted ? "black" : "white"}; + typeof inverted === "undefined" || inverted ? lightGray : "transparent"}; } display: flex; align-items: center; justify-content: center; gap: 4px; - padding: 1px; + padding: 2px; `; diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts index f123bb2b..a179c2bf 100644 --- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts +++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts @@ -23,6 +23,10 @@ abstract class AbstractContinueGUIClientProtocol { abstract deleteContextAtIndices(indices: number[]): void; + abstract setEditingAtIndices(indices: number[]): void; + + abstract setPinnedAtIndices(indices: number[]): void; + abstract toggleAddingHighlightedCode(): void; } diff --git a/extension/react-app/src/hooks/useContinueGUIProtocol.ts b/extension/react-app/src/hooks/useContinueGUIProtocol.ts index 49f200ae..2060dd7f 100644 --- a/extension/react-app/src/hooks/useContinueGUIProtocol.ts +++ b/extension/react-app/src/hooks/useContinueGUIProtocol.ts @@ -75,6 +75,14 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol { this.messenger.send("delete_context_at_indices", { indices }); } + setEditingAtIndices(indices: number[]) { + this.messenger.send("set_editing_at_indices", { indices }); + } + + setPinnedAtIndices(indices: number[]) { + this.messenger.send("set_pinned_at_indices", { indices }); + } + toggleAddingHighlightedCode(): void { this.messenger.send("toggle_adding_highlighted_code", {}); } diff --git a/extension/react-app/src/index.css b/extension/react-app/src/index.css index 6dc514ec..682551f8 100644 --- a/extension/react-app/src/index.css +++ b/extension/react-app/src/index.css @@ -10,19 +10,12 @@ --def-border-radius: 5px; } -@font-face { - font-family: "Mona Sans"; - src: url("assets/Mona-Sans.woff2") format("woff2 supports variations"), - url("assets/Mona-Sans.woff2") format("woff2-variations"); - font-weight: 200 900; - font-stretch: 75% 85%; -} - html, body, #root { height: 100%; background-color: var(--vsc-background); + font-family: "Lexend", sans-serif; } body { diff --git a/extension/react-app/src/main.tsx b/extension/react-app/src/main.tsx index 0b02575c..a76bced6 100644 --- a/extension/react-app/src/main.tsx +++ b/extension/react-app/src/main.tsx @@ -1,6 +1,8 @@ import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; +import { Provider } from "react-redux"; +import store from "./redux/store"; import "./index.css"; import posthog from "posthog-js"; @@ -17,7 +19,9 @@ posthog.init("phc_JS6XFROuNbhJtVCEdTSYk6gl5ArRrTNMpCcguAXlSPs", { ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( - + + + ); diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index e5320c6a..3cce30de 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -1,11 +1,13 @@ import styled from "styled-components"; -import { defaultBorderRadius, Loader } from "../components"; +import { defaultBorderRadius } from "../components"; +import Loader from "../components/Loader"; import ContinueButton from "../components/ContinueButton"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { FullState, HighlightedRangeContext } from "../../../schema/FullState"; +import { useCallback, useEffect, useRef, useState, useContext } from "react"; import { History } from "../../../schema/History"; import { HistoryNode } from "../../../schema/HistoryNode"; import StepContainer from "../components/StepContainer"; -import useContinueGUIProtocol from "../hooks/useWebsocket"; +import { GUIClientContext } from "../App"; import { BookOpen, ChatBubbleOvalLeftEllipsis, @@ -52,6 +54,7 @@ interface GUIProps { } function GUI(props: GUIProps) { + const client = useContext(GUIClientContext); const posthog = usePostHog(); const vscMachineId = useSelector( (state: RootStore) => state.config.vscMachineId @@ -70,7 +73,9 @@ function GUI(props: GUIProps) { const [usingFastModel, setUsingFastModel] = useState(false); const [waitingForSteps, setWaitingForSteps] = useState(false); const [userInputQueue, setUserInputQueue] = useState([]); - const [highlightedRanges, setHighlightedRanges] = useState([]); + const [highlightedRanges, setHighlightedRanges] = useState< + HighlightedRangeContext[] + >([]); const [addingHighlightedCode, setAddingHighlightedCode] = useState(false); const [availableSlashCommands, setAvailableSlashCommands] = useState< { name: string; description: string }[] @@ -112,7 +117,6 @@ function GUI(props: GUIProps) { const [feedbackDialogMessage, setFeedbackDialogMessage] = useState(""); const topGuiDivRef = useRef(null); - const client = useContinueGUIProtocol(); const [scrollTimeout, setScrollTimeout] = useState( null @@ -148,7 +152,7 @@ function GUI(props: GUIProps) { }, []); useEffect(() => { - client?.onStateUpdate((state) => { + client?.onStateUpdate((state: FullState) => { // Scroll only if user is at very bottom of the window. setUsingFastModel(state.default_model === "gpt-3.5-turbo"); const shouldScrollToBottom = @@ -289,7 +293,7 @@ function GUI(props: GUIProps) { > {typeof client === "undefined" && ( <> - +

Loading Continue server...

)} @@ -316,7 +320,8 @@ function GUI(props: GUIProps) { setStepsOpen(nextStepsOpen); }} onToggleAll={() => { - setStepsOpen((prev) => prev.map((_, index) => !prev[index])); + const shouldOpen = !stepsOpen[index]; + setStepsOpen((prev) => prev.map(() => shouldOpen)); }} key={index} onUserInput={(input: string) => { @@ -381,6 +386,7 @@ function GUI(props: GUIProps) { borderRadius: defaultBorderRadius, padding: "16px", margin: "16px", + zIndex: 100, }} hidden={!showDataSharingInfo} > diff --git a/extension/schema/FullState.d.ts b/extension/schema/FullState.d.ts new file mode 100644 index 00000000..981e772e --- /dev/null +++ b/extension/schema/FullState.d.ts @@ -0,0 +1,133 @@ +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type FullState = FullState1; +export type Name = string; +export type Hide = boolean; +export type Description = string; +export type SystemMessage = string; +export type Role = "assistant" | "user" | "system" | "function"; +export type Content = string; +export type Name1 = string; +export type Summary = string; +export type Name2 = string; +export type Arguments = string; +export type ChatContext = ChatMessage[]; +export type ManageOwnChatContext = boolean; +export type Depth = number; +export type Deleted = boolean; +export type Active = boolean; +export type Timeline = HistoryNode[]; +export type CurrentIndex = number; +export type Active1 = boolean; +export type UserInputQueue = string[]; +export type DefaultModel = string; +export type Filepath = string; +export type Line = number; +export type Character = number; +export type Contents = string; +export type Editing = boolean; +export type Pinned = boolean; +export type HighlightedRanges = HighlightedRangeContext[]; +export type Name3 = string; +export type Description1 = string; +export type SlashCommands = SlashCommandDescription[]; +export type AddingHighlightedCode = boolean; + +/** + * A full state of the program, including the history + */ +export interface FullState1 { + history: History; + active: Active1; + user_input_queue: UserInputQueue; + default_model: DefaultModel; + highlighted_ranges: HighlightedRanges; + slash_commands: SlashCommands; + adding_highlighted_code: AddingHighlightedCode; + [k: string]: unknown; +} +/** + * A history of steps taken and their results + */ +export interface History { + timeline: Timeline; + current_index: CurrentIndex; + [k: string]: unknown; +} +/** + * A point in history, a list of which make up History + */ +export interface HistoryNode { + step: Step; + observation?: Observation; + depth: Depth; + deleted?: Deleted; + active?: Active; + [k: string]: unknown; +} +export interface Step { + name?: Name; + hide?: Hide; + description?: Description; + system_message?: SystemMessage; + chat_context?: ChatContext; + manage_own_chat_context?: ManageOwnChatContext; + [k: string]: unknown; +} +export interface ChatMessage { + role: Role; + content?: Content; + name?: Name1; + summary: Summary; + function_call?: FunctionCall; + [k: string]: unknown; +} +export interface FunctionCall { + name: Name2; + arguments: Arguments; + [k: string]: unknown; +} +export interface Observation { + [k: string]: unknown; +} +/** + * Context for a highlighted range + */ +export interface HighlightedRangeContext { + range: RangeInFileWithContents; + editing: Editing; + pinned: Pinned; + [k: string]: unknown; +} +/** + * A range in a file with the contents of the range. + */ +export interface RangeInFileWithContents { + filepath: Filepath; + range: Range; + contents: Contents; + [k: string]: unknown; +} +/** + * A range in a file. 0-indexed. + */ +export interface Range { + start: Position; + end: Position; + [k: string]: unknown; +} +export interface Position { + line: Line; + character: Character; + [k: string]: unknown; +} +export interface SlashCommandDescription { + name: Name3; + description: Description1; + [k: string]: unknown; +} diff --git a/extension/src/debugPanel.ts b/extension/src/debugPanel.ts index b88c86f3..487bbedf 100644 --- a/extension/src/debugPanel.ts +++ b/extension/src/debugPanel.ts @@ -341,6 +341,10 @@ export function setupDebugPanel( + + + + Continue diff --git a/schema/json/FullState.json b/schema/json/FullState.json new file mode 100644 index 00000000..af0f25e1 --- /dev/null +++ b/schema/json/FullState.json @@ -0,0 +1,304 @@ +{ + "title": "FullState", + "$ref": "#/definitions/src__continuedev__core__main__FullState", + "definitions": { + "FunctionCall": { + "title": "FunctionCall", + "type": "object", + "properties": { + "name": { + "title": "Name", + "type": "string" + }, + "arguments": { + "title": "Arguments", + "type": "string" + } + }, + "required": [ + "name", + "arguments" + ] + }, + "ChatMessage": { + "title": "ChatMessage", + "type": "object", + "properties": { + "role": { + "title": "Role", + "enum": [ + "assistant", + "user", + "system", + "function" + ], + "type": "string" + }, + "content": { + "title": "Content", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + }, + "summary": { + "title": "Summary", + "type": "string" + }, + "function_call": { + "$ref": "#/definitions/FunctionCall" + } + }, + "required": [ + "role", + "summary" + ] + }, + "Step": { + "title": "Step", + "type": "object", + "properties": { + "name": { + "title": "Name", + "type": "string" + }, + "hide": { + "title": "Hide", + "default": false, + "type": "boolean" + }, + "description": { + "title": "Description", + "type": "string" + }, + "system_message": { + "title": "System Message", + "type": "string" + }, + "chat_context": { + "title": "Chat Context", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/ChatMessage" + } + }, + "manage_own_chat_context": { + "title": "Manage Own Chat Context", + "default": false, + "type": "boolean" + } + } + }, + "Observation": { + "title": "Observation", + "type": "object", + "properties": {} + }, + "HistoryNode": { + "title": "HistoryNode", + "description": "A point in history, a list of which make up History", + "type": "object", + "properties": { + "step": { + "$ref": "#/definitions/Step" + }, + "observation": { + "$ref": "#/definitions/Observation" + }, + "depth": { + "title": "Depth", + "type": "integer" + }, + "deleted": { + "title": "Deleted", + "default": false, + "type": "boolean" + }, + "active": { + "title": "Active", + "default": true, + "type": "boolean" + } + }, + "required": [ + "step", + "depth" + ] + }, + "History": { + "title": "History", + "description": "A history of steps taken and their results", + "type": "object", + "properties": { + "timeline": { + "title": "Timeline", + "type": "array", + "items": { + "$ref": "#/definitions/HistoryNode" + } + }, + "current_index": { + "title": "Current Index", + "type": "integer" + } + }, + "required": [ + "timeline", + "current_index" + ] + }, + "Position": { + "title": "Position", + "type": "object", + "properties": { + "line": { + "title": "Line", + "type": "integer" + }, + "character": { + "title": "Character", + "type": "integer" + } + }, + "required": [ + "line", + "character" + ] + }, + "Range": { + "title": "Range", + "description": "A range in a file. 0-indexed.", + "type": "object", + "properties": { + "start": { + "$ref": "#/definitions/Position" + }, + "end": { + "$ref": "#/definitions/Position" + } + }, + "required": [ + "start", + "end" + ] + }, + "RangeInFileWithContents": { + "title": "RangeInFileWithContents", + "description": "A range in a file with the contents of the range.", + "type": "object", + "properties": { + "filepath": { + "title": "Filepath", + "type": "string" + }, + "range": { + "$ref": "#/definitions/Range" + }, + "contents": { + "title": "Contents", + "type": "string" + } + }, + "required": [ + "filepath", + "range", + "contents" + ] + }, + "HighlightedRangeContext": { + "title": "HighlightedRangeContext", + "description": "Context for a highlighted range", + "type": "object", + "properties": { + "range": { + "$ref": "#/definitions/RangeInFileWithContents" + }, + "editing": { + "title": "Editing", + "type": "boolean" + }, + "pinned": { + "title": "Pinned", + "type": "boolean" + } + }, + "required": [ + "range", + "editing", + "pinned" + ] + }, + "SlashCommandDescription": { + "title": "SlashCommandDescription", + "type": "object", + "properties": { + "name": { + "title": "Name", + "type": "string" + }, + "description": { + "title": "Description", + "type": "string" + } + }, + "required": [ + "name", + "description" + ] + }, + "src__continuedev__core__main__FullState": { + "title": "FullState", + "description": "A full state of the program, including the history", + "type": "object", + "properties": { + "history": { + "$ref": "#/definitions/History" + }, + "active": { + "title": "Active", + "type": "boolean" + }, + "user_input_queue": { + "title": "User Input Queue", + "type": "array", + "items": { + "type": "string" + } + }, + "default_model": { + "title": "Default Model", + "type": "string" + }, + "highlighted_ranges": { + "title": "Highlighted Ranges", + "type": "array", + "items": { + "$ref": "#/definitions/HighlightedRangeContext" + } + }, + "slash_commands": { + "title": "Slash Commands", + "type": "array", + "items": { + "$ref": "#/definitions/SlashCommandDescription" + } + }, + "adding_highlighted_code": { + "title": "Adding Highlighted Code", + "type": "boolean" + } + }, + "required": [ + "history", + "active", + "user_input_queue", + "default_model", + "highlighted_ranges", + "slash_commands", + "adding_highlighted_code" + ] + } + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 5709c9ae003ededb520ee641cae8c8570d4c93af Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 9 Jul 2023 14:12:36 -0700 Subject: sdk.get_code_context --- continuedev/src/continuedev/core/autopilot.py | 6 ++-- continuedev/src/continuedev/core/main.py | 1 + continuedev/src/continuedev/core/sdk.py | 7 ++++- continuedev/src/continuedev/steps/main.py | 38 +++++++++++-------------- extension/react-app/src/components/ComboBox.tsx | 6 ++-- extension/schema/FullState.d.ts | 2 ++ schema/json/FullState.json | 7 ++++- 7 files changed, 36 insertions(+), 31 deletions(-) (limited to 'extension/schema') diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py index b583d682..5c3baafd 100644 --- a/continuedev/src/continuedev/core/autopilot.py +++ b/continuedev/src/continuedev/core/autopilot.py @@ -157,8 +157,6 @@ class Autopilot(ContinueBaseModel): # Make sure all filepaths are relative to workspace workspace_path = self.continue_sdk.ide.workspace_directory - for rif in range_in_files: - rif.filepath = os.path.basename(rif.filepath) # If not adding highlighted code if not self._adding_highlighted_code: @@ -170,7 +168,7 @@ class Autopilot(ContinueBaseModel): # Otherwise, replace the current range with the new one # This is the first range to be highlighted self._highlighted_ranges = [HighlightedRangeContext( - range=range_in_files[0], editing=True, pinned=False)] + range=range_in_files[0], editing=True, pinned=False, display_name=os.path.basename(range_in_files[0].filepath))] await self.update_subscribers() return @@ -193,7 +191,7 @@ class Autopilot(ContinueBaseModel): new_ranges.append(rif) self._highlighted_ranges = new_ranges + [HighlightedRangeContext( - range=rif, editing=False, pinned=False + range=rif, editing=False, pinned=False, display_name=os.path.basename(rif.filepath) ) for rif in range_in_files] self._make_sure_is_editing_range() diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py index 4ea17f20..88690c83 100644 --- a/continuedev/src/continuedev/core/main.py +++ b/continuedev/src/continuedev/core/main.py @@ -205,6 +205,7 @@ class HighlightedRangeContext(ContinueBaseModel): range: RangeInFileWithContents editing: bool pinned: bool + display_name: str class FullState(ContinueBaseModel): diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py index ed670799..8649cd58 100644 --- a/continuedev/src/continuedev/core/sdk.py +++ b/continuedev/src/continuedev/core/sdk.py @@ -13,7 +13,7 @@ from ..libs.llm.hf_inference_api import HuggingFaceInferenceAPI from ..libs.llm.openai import OpenAI from .observation import Observation from ..server.ide_protocol import AbstractIdeProtocolServer -from .main import Context, ContinueCustomException, History, Step, ChatMessage, ChatMessageRole +from .main import Context, ContinueCustomException, HighlightedRangeContext, History, Step, ChatMessage, ChatMessageRole from ..steps.core.core import * from ..libs.llm.proxy_server import ProxyServer @@ -178,6 +178,11 @@ class ContinueSDK(AbstractContinueSDK): else: return load_global_config() + def get_code_context(self, only_editing: bool = False) -> List[RangeInFileWithContents]: + context = list(filter(lambda x: x.editing, self.__autopilot._highlighted_ranges) + ) if only_editing else self.__autopilot._highlighted_ranges + return [c.range for c in context] + def update_default_model(self, model: str): config = self.config config.default_model = model diff --git a/continuedev/src/continuedev/steps/main.py b/continuedev/src/continuedev/steps/main.py index 5ccffbfe..0a20ddd7 100644 --- a/continuedev/src/continuedev/steps/main.py +++ b/continuedev/src/continuedev/steps/main.py @@ -97,7 +97,7 @@ class FasterEditHighlightedCodeStep(Step): return "Editing highlighted code" async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]: - range_in_files = await sdk.ide.getHighlightedCode() + range_in_files = await sdk.get_code_context(only_editing=True) if len(range_in_files) == 0: # Get the full contents of all open files files = await sdk.ide.getOpenFiles() @@ -105,21 +105,16 @@ class FasterEditHighlightedCodeStep(Step): for file in files: contents[file] = await sdk.ide.readFile(file) - range_in_files = [RangeInFile.from_entire_file( + range_in_files = [RangeInFileWithContents.from_entire_file( filepath, content) for filepath, content in contents.items()] - rif_with_contents = [] - for range_in_file in range_in_files: - file_contents = await sdk.ide.readRangeInFile(range_in_file) - rif_with_contents.append( - RangeInFileWithContents.from_range_in_file(range_in_file, file_contents)) - enc_dec = MarkdownStyleEncoderDecoder(rif_with_contents) + enc_dec = MarkdownStyleEncoderDecoder(range_in_files) code_string = enc_dec.encode() prompt = self._prompt.format( code=code_string, user_input=self.user_input) rif_dict = {} - for rif in rif_with_contents: + for rif in range_in_files: rif_dict[rif.filepath] = rif.contents completion = await sdk.models.gpt35.complete(prompt) @@ -193,7 +188,7 @@ class StarCoderEditHighlightedCodeStep(Step): return await models.gpt35.complete(f"{self._prompt_and_completion}\n\nPlease give brief a description of the changes made above using markdown bullet points:") async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]: - range_in_files = await sdk.ide.getHighlightedCode() + range_in_files = await sdk.get_code_context(only_editing=True) found_highlighted_code = len(range_in_files) > 0 if not found_highlighted_code: # Get the full contents of all open files @@ -202,20 +197,14 @@ class StarCoderEditHighlightedCodeStep(Step): for file in files: contents[file] = await sdk.ide.readFile(file) - range_in_files = [RangeInFile.from_entire_file( + range_in_files = [RangeInFileWithContents.from_entire_file( filepath, content) for filepath, content in contents.items()] - rif_with_contents = [] - for range_in_file in range_in_files: - file_contents = await sdk.ide.readRangeInFile(range_in_file) - rif_with_contents.append( - RangeInFileWithContents.from_range_in_file(range_in_file, file_contents)) - rif_dict = {} - for rif in rif_with_contents: + for rif in range_in_files: rif_dict[rif.filepath] = rif.contents - for rif in rif_with_contents: + for rif in range_in_files: prompt = self._prompt.format( code=rif.contents, user_request=self.user_input) @@ -255,7 +244,7 @@ class EditHighlightedCodeStep(Step): return "Editing code" async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]: - range_in_files = await sdk.ide.getHighlightedCode() + range_in_files = sdk.get_code_context(only_editing=True) if len(range_in_files) == 0: # Get the full contents of all open files files = await sdk.ide.getOpenFiles() @@ -263,7 +252,7 @@ class EditHighlightedCodeStep(Step): for file in files: contents[file] = await sdk.ide.readFile(file) - range_in_files = [RangeInFile.from_entire_file( + range_in_files = [RangeInFileWithContents.from_entire_file( filepath, content) for filepath, content in contents.items()] # If still no highlighted code, create a new file and edit there @@ -271,7 +260,12 @@ class EditHighlightedCodeStep(Step): # Create a new file new_file_path = "new_file.txt" await sdk.add_file(new_file_path, "") - range_in_files = [RangeInFile.from_entire_file(new_file_path, "")] + range_in_files = [ + RangeInFileWithContents.from_entire_file(new_file_path, "")] + + range_in_files = list(map(lambda x: RangeInFile( + filepath=x.filepath, range=x.range + ), range_in_files)) await sdk.run_step(DefaultModelEditCodeStep(user_input=self.user_input, range_in_files=range_in_files)) diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx index e6632360..801c3a03 100644 --- a/extension/react-app/src/components/ComboBox.tsx +++ b/extension/react-app/src/components/ComboBox.tsx @@ -224,8 +224,8 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { editing={section.editing} pinned={section.pinned} index={idx} - key={`${section.filepath}${idx}`} - title={`${section.range.filepath} (${ + key={`${section.display_name}${idx}`} + title={`${section.display_name} (${ section.range.range.start.line + 1 }-${section.range.range.end.line + 1})`} onDelete={() => { @@ -372,7 +372,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { > {highlightedCodeSections.map((section, idx) => ( <> -

{section.range.filepath}

+

{section.display_name}

{section.range.contents} diff --git a/extension/schema/FullState.d.ts b/extension/schema/FullState.d.ts index 981e772e..abb0832d 100644 --- a/extension/schema/FullState.d.ts +++ b/extension/schema/FullState.d.ts @@ -32,6 +32,7 @@ export type Character = number; export type Contents = string; export type Editing = boolean; export type Pinned = boolean; +export type DisplayName = string; export type HighlightedRanges = HighlightedRangeContext[]; export type Name3 = string; export type Description1 = string; @@ -102,6 +103,7 @@ export interface HighlightedRangeContext { range: RangeInFileWithContents; editing: Editing; pinned: Pinned; + display_name: DisplayName; [k: string]: unknown; } /** diff --git a/schema/json/FullState.json b/schema/json/FullState.json index af0f25e1..5a7e9d10 100644 --- a/schema/json/FullState.json +++ b/schema/json/FullState.json @@ -222,12 +222,17 @@ "pinned": { "title": "Pinned", "type": "boolean" + }, + "display_name": { + "title": "Display Name", + "type": "string" } }, "required": [ "range", "editing", - "pinned" + "pinned", + "display_name" ] }, "SlashCommandDescription": { -- cgit v1.2.3-70-g09d2 From 53ac7b93f456b471eaa7f03e015e2d8c0ef393e5 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Tue, 18 Jul 2023 14:02:03 -0700 Subject: error handle on invalid config file, don't immediately show loading message --- continuedev/src/continuedev/core/sdk.py | 19 ++++++++++- extension/package-lock.json | 4 +-- extension/package.json | 2 +- extension/schema/FullState.d.ts | 2 ++ extension/schema/History.d.ts | 2 ++ extension/schema/HistoryNode.d.ts | 2 ++ extension/src/activation/activate.ts | 48 ++++++++++++++++++++-------- extension/src/activation/environmentSetup.ts | 2 +- extension/src/extension.ts | 12 +------ schema/json/FullState.json | 8 +++++ schema/json/History.json | 8 +++++ schema/json/HistoryNode.json | 8 +++++ 12 files changed, 88 insertions(+), 29 deletions(-) (limited to 'extension/schema') diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py index 53214384..37a51efa 100644 --- a/continuedev/src/continuedev/core/sdk.py +++ b/continuedev/src/continuedev/core/sdk.py @@ -15,7 +15,7 @@ from ..libs.llm.anthropic import AnthropicLLM from ..libs.llm.ggml import GGML from .observation import Observation from ..server.ide_protocol import AbstractIdeProtocolServer -from .main import Context, ContinueCustomException, History, Step, ChatMessage +from .main import Context, ContinueCustomException, History, HistoryNode, Step, ChatMessage from ..steps.core.core import * from ..libs.llm.proxy_server import ProxyServer @@ -155,6 +155,23 @@ class ContinueSDK(AbstractContinueSDK): @classmethod async def create(cls, autopilot: Autopilot) -> "ContinueSDK": sdk = ContinueSDK(autopilot) + + try: + config = sdk._load_config() + sdk.config = config + except Exception as e: + print(e) + sdk.config = ContinueConfig() + msg_step = MessageStep( + name="Invalid Continue Config File", message=e.__repr__()) + msg_step.description = e.__repr__() + sdk.history.add_node(HistoryNode( + step=msg_step, + observation=None, + depth=0, + active=False + )) + sdk.models = await Models.create(sdk) return sdk diff --git a/extension/package-lock.json b/extension/package-lock.json index 107a7001..6818857b 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.179", + "version": "0.0.181", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.179", + "version": "0.0.181", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index 89c6daf5..b37bb1b6 100644 --- a/extension/package.json +++ b/extension/package.json @@ -14,7 +14,7 @@ "displayName": "Continue", "pricing": "Free", "description": "The open-source coding autopilot", - "version": "0.0.179", + "version": "0.0.181", "publisher": "Continue", "engines": { "vscode": "^1.67.0" diff --git a/extension/schema/FullState.d.ts b/extension/schema/FullState.d.ts index abb0832d..1b7b1f3b 100644 --- a/extension/schema/FullState.d.ts +++ b/extension/schema/FullState.d.ts @@ -21,6 +21,7 @@ export type ManageOwnChatContext = boolean; export type Depth = number; export type Deleted = boolean; export type Active = boolean; +export type Logs = string[]; export type Timeline = HistoryNode[]; export type CurrentIndex = number; export type Active1 = boolean; @@ -69,6 +70,7 @@ export interface HistoryNode { depth: Depth; deleted?: Deleted; active?: Active; + logs?: Logs; [k: string]: unknown; } export interface Step { diff --git a/extension/schema/History.d.ts b/extension/schema/History.d.ts index 6eb8ad81..90124f4a 100644 --- a/extension/schema/History.d.ts +++ b/extension/schema/History.d.ts @@ -21,6 +21,7 @@ export type ManageOwnChatContext = boolean; export type Depth = number; export type Deleted = boolean; export type Active = boolean; +export type Logs = string[]; export type Timeline = HistoryNode[]; export type CurrentIndex = number; @@ -41,6 +42,7 @@ export interface HistoryNode { depth: Depth; deleted?: Deleted; active?: Active; + logs?: Logs; [k: string]: unknown; } export interface Step { diff --git a/extension/schema/HistoryNode.d.ts b/extension/schema/HistoryNode.d.ts index bc77be89..5ad32061 100644 --- a/extension/schema/HistoryNode.d.ts +++ b/extension/schema/HistoryNode.d.ts @@ -21,6 +21,7 @@ export type ManageOwnChatContext = boolean; export type Depth = number; export type Deleted = boolean; export type Active = boolean; +export type Logs = string[]; /** * A point in history, a list of which make up History @@ -31,6 +32,7 @@ export interface HistoryNode1 { depth: Depth; deleted?: Deleted; active?: Active; + logs?: Logs; [k: string]: unknown; } export interface Step { diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts index 5c6ffa02..8ea08e89 100644 --- a/extension/src/activation/activate.ts +++ b/extension/src/activation/activate.ts @@ -36,22 +36,44 @@ export async function activateExtension(context: vscode.ExtensionContext) { }) .catch((e) => console.log("Error checking for extension updates: ", e)); - // Start the Python server - await new Promise((resolve, reject) => { - vscode.window.withProgress( - { - location: vscode.ProgressLocation.Notification, - title: - "Starting Continue Server... (it may take a minute to download Python packages)", - cancellable: false, - }, - async (progress, token) => { - await startContinuePythonServer(); - resolve(null); + // Wrap the server start logic in a new Promise + const serverStartPromise = new Promise((resolve, reject) => { + let serverStarted = false; + + // Start the server and set serverStarted to true when done + startContinuePythonServer().then(() => { + serverStarted = true; + resolve(null); + }); + + // Wait for 2 seconds + setTimeout(() => { + // If the server hasn't started after 2 seconds, show the notification + if (!serverStarted) { + vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: + "Starting Continue Server... (it may take a minute to download Python packages)", + cancellable: false, + }, + async (progress, token) => { + // Wait for the server to start + while (!serverStarted) { + await new Promise((innerResolve) => + setTimeout(innerResolve, 1000) + ); + } + return Promise.resolve(); + } + ); } - ); + }, 2000); }); + // Await the server start promise + await serverStartPromise; + // Register commands and providers sendTelemetryEvent(TelemetryEvent.ExtensionActivated); registerAllCodeLensProviders(context); diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 69a3b75a..c341db39 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -39,7 +39,7 @@ async function retryThenFail( // Show corresponding error message depending on the platform let msg = - "Failed to set up Continue extension. Please email nate@continue.dev and we'll get this fixed ASAP!"; + "Failed to set up Continue extension. Please email hi@continue.dev and we'll get this fixed ASAP!"; try { switch (process.platform) { case "win32": diff --git a/extension/src/extension.ts b/extension/src/extension.ts index 6959ec05..f2e580a1 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -17,15 +17,5 @@ async function dynamicImportAndActivate(context: vscode.ExtensionContext) { } export function activate(context: vscode.ExtensionContext) { - // Only show progress if we have to setup - vscode.window.withProgress( - { - location: vscode.ProgressLocation.Notification, - title: "Setting up Continue extension...", - cancellable: false, - }, - async () => { - dynamicImportAndActivate(context); - } - ); + dynamicImportAndActivate(context); } diff --git a/schema/json/FullState.json b/schema/json/FullState.json index 5a7e9d10..62ed337b 100644 --- a/schema/json/FullState.json +++ b/schema/json/FullState.json @@ -120,6 +120,14 @@ "title": "Active", "default": true, "type": "boolean" + }, + "logs": { + "title": "Logs", + "default": [], + "type": "array", + "items": { + "type": "string" + } } }, "required": [ diff --git a/schema/json/History.json b/schema/json/History.json index ee797412..56415520 100644 --- a/schema/json/History.json +++ b/schema/json/History.json @@ -120,6 +120,14 @@ "title": "Active", "default": true, "type": "boolean" + }, + "logs": { + "title": "Logs", + "default": [], + "type": "array", + "items": { + "type": "string" + } } }, "required": [ diff --git a/schema/json/HistoryNode.json b/schema/json/HistoryNode.json index d0e12ac5..81e239b3 100644 --- a/schema/json/HistoryNode.json +++ b/schema/json/HistoryNode.json @@ -120,6 +120,14 @@ "title": "Active", "default": true, "type": "boolean" + }, + "logs": { + "title": "Logs", + "default": [], + "type": "array", + "items": { + "type": "string" + } } }, "required": [ -- cgit v1.2.3-70-g09d2 From 4d7e72970f770eb49627589fb142c93dfb6fd73b Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sat, 22 Jul 2023 22:37:13 -0700 Subject: @ feature (very large commit) --- continuedev/poetry.lock | 340 ++++++++++++++++++++- continuedev/pyproject.toml | 2 + continuedev/src/continuedev/core/autopilot.py | 138 ++------- continuedev/src/continuedev/core/config.py | 3 + continuedev/src/continuedev/core/context.py | 205 +++++++++++++ .../src/continuedev/core/context_manager.py | 119 -------- continuedev/src/continuedev/core/main.py | 59 +++- continuedev/src/continuedev/core/sdk.py | 31 +- .../highlighted_code_context_provider.py | 191 ++++++++++++ continuedev/src/continuedev/libs/util/paths.py | 20 +- .../src/continuedev/models/generate_json_schema.py | 3 + continuedev/src/continuedev/server/gui.py | 37 +-- continuedev/src/continuedev/server/gui_protocol.py | 10 +- continuedev/src/continuedev/server/main.py | 28 +- .../src/continuedev/server/meilisearch_server.py | 56 ++++ .../src/continuedev/server/session_manager.py | 6 +- extension/react-app/package-lock.json | 98 ++++++ extension/react-app/package.json | 1 + extension/react-app/src/components/ComboBox.tsx | 174 ++++++----- extension/react-app/src/components/PillButton.tsx | 87 ++++-- .../react-app/src/components/StepContainer.tsx | 29 +- .../src/components/StyledMarkdownPreview.tsx | 37 +++ extension/react-app/src/components/TextDialog.tsx | 2 +- .../src/hooks/AbstractContinueGUIClientProtocol.ts | 8 +- .../src/hooks/ContinueGUIClientProtocol.ts | 15 +- extension/react-app/src/pages/gui.tsx | 81 ++--- .../src/redux/selectors/uiStateSelectors.ts | 5 + .../react-app/src/redux/slices/uiStateSlice.ts | 24 ++ extension/react-app/src/redux/store.ts | 6 + extension/schema/ContextItem.d.ts | 45 +++ extension/schema/FullState.d.ts | 65 ++-- schema/json/ContextItem.json | 76 +++++ schema/json/FullState.json | 132 ++++---- 33 files changed, 1554 insertions(+), 579 deletions(-) create mode 100644 continuedev/src/continuedev/core/context.py delete mode 100644 continuedev/src/continuedev/core/context_manager.py create mode 100644 continuedev/src/continuedev/libs/context_providers/highlighted_code_context_provider.py create mode 100644 continuedev/src/continuedev/server/meilisearch_server.py create mode 100644 extension/react-app/src/components/StyledMarkdownPreview.tsx create mode 100644 extension/react-app/src/redux/selectors/uiStateSelectors.ts create mode 100644 extension/react-app/src/redux/slices/uiStateSlice.ts create mode 100644 extension/schema/ContextItem.d.ts create mode 100644 schema/json/ContextItem.json (limited to 'extension/schema') diff --git a/continuedev/poetry.lock b/continuedev/poetry.lock index 1cd4a591..b67128fd 100644 --- a/continuedev/poetry.lock +++ b/continuedev/poetry.lock @@ -220,6 +220,24 @@ files = [ {file = "boltons-23.0.0.tar.gz", hash = "sha256:8c50a71829525835ca3c849c7ed2511610c972b4dddfcd41a4a5447222beb4b0"}, ] +[[package]] +name = "camel-converter" +version = "3.0.2" +description = "Converts a string from snake case to camel case or camel case to snake case" +category = "main" +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "camel_converter-3.0.2-py3-none-any.whl", hash = "sha256:88e5d91be5b2dff9c0748ba515774c3421088922d9e77c39f8742eb41cb7db88"}, + {file = "camel_converter-3.0.2.tar.gz", hash = "sha256:3b3d076e824ae979b271b4d497c90514c2b218811f76b0c368fb69da2556fe07"}, +] + +[package.dependencies] +pydantic = {version = ">=1.8.2", optional = true, markers = "extra == \"pydantic\""} + +[package.extras] +pydantic = ["pydantic (>=1.8.2)"] + [[package]] name = "certifi" version = "2022.12.7" @@ -232,6 +250,83 @@ files = [ {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, ] +[[package]] +name = "cffi" +version = "1.15.1" +description = "Foreign Function Interface for Python calling C code." +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, +] + +[package.dependencies] +pycparser = "*" + [[package]] name = "charset-normalizer" version = "3.1.0" @@ -356,6 +451,52 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "cryptography" +version = "41.0.2" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "cryptography-41.0.2-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:01f1d9e537f9a15b037d5d9ee442b8c22e3ae11ce65ea1f3316a41c78756b711"}, + {file = "cryptography-41.0.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:079347de771f9282fbfe0e0236c716686950c19dee1b76240ab09ce1624d76d7"}, + {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:439c3cc4c0d42fa999b83ded80a9a1fb54d53c58d6e59234cfe97f241e6c781d"}, + {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f14ad275364c8b4e525d018f6716537ae7b6d369c094805cae45300847e0894f"}, + {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:84609ade00a6ec59a89729e87a503c6e36af98ddcd566d5f3be52e29ba993182"}, + {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:49c3222bb8f8e800aead2e376cbef687bc9e3cb9b58b29a261210456a7783d83"}, + {file = "cryptography-41.0.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d73f419a56d74fef257955f51b18d046f3506270a5fd2ac5febbfa259d6c0fa5"}, + {file = "cryptography-41.0.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:2a034bf7d9ca894720f2ec1d8b7b5832d7e363571828037f9e0c4f18c1b58a58"}, + {file = "cryptography-41.0.2-cp37-abi3-win32.whl", hash = "sha256:d124682c7a23c9764e54ca9ab5b308b14b18eba02722b8659fb238546de83a76"}, + {file = "cryptography-41.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:9c3fe6534d59d071ee82081ca3d71eed3210f76ebd0361798c74abc2bcf347d4"}, + {file = "cryptography-41.0.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a719399b99377b218dac6cf547b6ec54e6ef20207b6165126a280b0ce97e0d2a"}, + {file = "cryptography-41.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:182be4171f9332b6741ee818ec27daff9fb00349f706629f5cbf417bd50e66fd"}, + {file = "cryptography-41.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7a9a3bced53b7f09da251685224d6a260c3cb291768f54954e28f03ef14e3766"}, + {file = "cryptography-41.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f0dc40e6f7aa37af01aba07277d3d64d5a03dc66d682097541ec4da03cc140ee"}, + {file = "cryptography-41.0.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:674b669d5daa64206c38e507808aae49904c988fa0a71c935e7006a3e1e83831"}, + {file = "cryptography-41.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7af244b012711a26196450d34f483357e42aeddb04128885d95a69bd8b14b69b"}, + {file = "cryptography-41.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9b6d717393dbae53d4e52684ef4f022444fc1cce3c48c38cb74fca29e1f08eaa"}, + {file = "cryptography-41.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:192255f539d7a89f2102d07d7375b1e0a81f7478925b3bc2e0549ebf739dae0e"}, + {file = "cryptography-41.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f772610fe364372de33d76edcd313636a25684edb94cee53fd790195f5989d14"}, + {file = "cryptography-41.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b332cba64d99a70c1e0836902720887fb4529ea49ea7f5462cf6640e095e11d2"}, + {file = "cryptography-41.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9a6673c1828db6270b76b22cc696f40cde9043eb90373da5c2f8f2158957f42f"}, + {file = "cryptography-41.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:342f3767e25876751e14f8459ad85e77e660537ca0a066e10e75df9c9e9099f0"}, + {file = "cryptography-41.0.2.tar.gz", hash = "sha256:7d230bf856164de164ecb615ccc14c7fc6de6906ddd5b491f3af90d3514c925c"}, +] + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] +docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +nox = ["nox"] +pep8test = ["black", "check-sdist", "mypy", "ruff"] +sdist = ["build"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test-randomorder = ["pytest-randomly"] + [[package]] name = "dataclasses-json" version = "0.5.7" @@ -376,6 +517,24 @@ typing-inspect = ">=0.4.0" [package.extras] dev = ["flake8", "hypothesis", "ipython", "mypy (>=0.710)", "portray", "pytest (>=6.2.3)", "simplejson", "types-dataclasses"] +[[package]] +name = "deprecated" +version = "1.2.14" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"}, + {file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"}, +] + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] + [[package]] name = "diff-match-patch" version = "20230430" @@ -816,6 +975,22 @@ files = [ [package.dependencies] marshmallow = ">=2.0.0" +[[package]] +name = "meilisearch" +version = "0.28.1" +description = "The python client for Meilisearch API." +category = "main" +optional = false +python-versions = ">=3.8" +files = [ + {file = "meilisearch-0.28.1-py3-none-any.whl", hash = "sha256:b4cfaf140fc323c429a4e174b801bcc6dddef88bf901560ebf2fc5c0014099b5"}, + {file = "meilisearch-0.28.1.tar.gz", hash = "sha256:4e8627abe1394f04125c99e60f9f4356ba200effe5735ce9b8a44b09e3c6403c"}, +] + +[package.dependencies] +camel-converter = {version = "*", extras = ["pydantic"]} +requests = "*" + [[package]] name = "monotonic" version = "1.6" @@ -1198,6 +1373,18 @@ files = [ [package.extras] test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + [[package]] name = "pydantic" version = "1.10.7" @@ -1251,6 +1438,72 @@ typing-extensions = ">=4.2.0" dotenv = ["python-dotenv (>=0.10.4)"] email = ["email-validator (>=1.0.3)"] +[[package]] +name = "pygithub" +version = "1.59.0" +description = "Use the full Github API v3" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "PyGithub-1.59.0-py3-none-any.whl", hash = "sha256:126bdbae72087d8d038b113aab6b059b4553cb59348e3024bb1a1cae406ace9e"}, + {file = "PyGithub-1.59.0.tar.gz", hash = "sha256:6e05ff49bac3caa7d1d6177a10c6e55a3e20c85b92424cc198571fd0cf786690"}, +] + +[package.dependencies] +deprecated = "*" +pyjwt = {version = ">=2.4.0", extras = ["crypto"]} +pynacl = ">=1.4.0" +requests = ">=2.14.0" + +[[package]] +name = "pyjwt" +version = "2.8.0" +description = "JSON Web Token implementation in Python" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, + {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, +] + +[package.dependencies] +cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""} + +[package.extras] +crypto = ["cryptography (>=3.4.0)"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] + +[[package]] +name = "pynacl" +version = "1.5.0" +description = "Python binding to the Networking and Cryptography (NaCl) library" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858"}, + {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b"}, + {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff"}, + {file = "PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"}, + {file = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"}, + {file = "PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba"}, +] + +[package.dependencies] +cffi = ">=1.4.1" + +[package.extras] +docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] +tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] + [[package]] name = "pyrsistent" version = "0.19.3" @@ -1935,6 +2188,91 @@ files = [ {file = "websockets-11.0.2.tar.gz", hash = "sha256:b1a69701eb98ed83dd099de4a686dc892c413d974fa31602bc00aca7cb988ac9"}, ] +[[package]] +name = "wrapt" +version = "1.15.0" +description = "Module for decorators, wrappers and monkey patching." +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +files = [ + {file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"}, + {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"}, + {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"}, + {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46"}, + {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c"}, + {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09"}, + {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079"}, + {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e"}, + {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a"}, + {file = "wrapt-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923"}, + {file = "wrapt-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee"}, + {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727"}, + {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7"}, + {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0"}, + {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec"}, + {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90"}, + {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975"}, + {file = "wrapt-1.15.0-cp310-cp310-win32.whl", hash = "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1"}, + {file = "wrapt-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e"}, + {file = "wrapt-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7"}, + {file = "wrapt-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72"}, + {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb"}, + {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e"}, + {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c"}, + {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3"}, + {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92"}, + {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98"}, + {file = "wrapt-1.15.0-cp311-cp311-win32.whl", hash = "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416"}, + {file = "wrapt-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705"}, + {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29"}, + {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd"}, + {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb"}, + {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248"}, + {file = "wrapt-1.15.0-cp35-cp35m-win32.whl", hash = "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559"}, + {file = "wrapt-1.15.0-cp35-cp35m-win_amd64.whl", hash = "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"}, + {file = "wrapt-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba"}, + {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752"}, + {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364"}, + {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475"}, + {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8"}, + {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418"}, + {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2"}, + {file = "wrapt-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1"}, + {file = "wrapt-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420"}, + {file = "wrapt-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317"}, + {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e"}, + {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e"}, + {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0"}, + {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019"}, + {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034"}, + {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653"}, + {file = "wrapt-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0"}, + {file = "wrapt-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e"}, + {file = "wrapt-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145"}, + {file = "wrapt-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f"}, + {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd"}, + {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b"}, + {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f"}, + {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6"}, + {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094"}, + {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7"}, + {file = "wrapt-1.15.0-cp38-cp38-win32.whl", hash = "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b"}, + {file = "wrapt-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1"}, + {file = "wrapt-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86"}, + {file = "wrapt-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c"}, + {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d"}, + {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc"}, + {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29"}, + {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a"}, + {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8"}, + {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9"}, + {file = "wrapt-1.15.0-cp39-cp39-win32.whl", hash = "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff"}, + {file = "wrapt-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6"}, + {file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"}, + {file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"}, +] + [[package]] name = "yarl" version = "1.9.2" @@ -2042,4 +2380,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "3fcd19c11b9c338a181e591b56e21d59c7834abff431fb9f40cc1ea874b64557" +content-hash = "83880c8de27a4094fa8e695bd8db5d4053fc2d61ffc028f09cfa097f315c35f2" diff --git a/continuedev/pyproject.toml b/continuedev/pyproject.toml index 0abc9504..64d5e90c 100644 --- a/continuedev/pyproject.toml +++ b/continuedev/pyproject.toml @@ -27,6 +27,8 @@ directory-tree = "^0.0.3.1" anthropic = "^0.3.4" chevron = "^0.14.0" psutil = "^5.9.5" +meilisearch = "^0.28.1" +pygithub = "^1.59.0" [tool.poetry.scripts] typegen = "src.continuedev.models.generate_json_schema:main" diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py index abda50b0..c0f95414 100644 --- a/continuedev/src/continuedev/core/autopilot.py +++ b/continuedev/src/continuedev/core/autopilot.py @@ -9,10 +9,12 @@ from pydantic import root_validator from ..models.filesystem import RangeInFileWithContents from ..models.filesystem_edit import FileEditWithFullContents from .observation import Observation, InternalErrorObservation +from .context import ContextItem, ContextItemDescription, ContextItemId, ContextManager +from ..libs.context_providers.highlighted_code_context_provider import HighlightedCodeContextProvider from ..server.ide_protocol import AbstractIdeProtocolServer from ..libs.util.queue import AsyncSubscriptionQueue from ..models.main import ContinueBaseModel -from .main import Context, ContinueCustomException, HighlightedRangeContext, Policy, History, FullState, Step, HistoryNode +from .main import Context, ContinueCustomException, Policy, History, FullState, Step, HistoryNode from ..steps.core.core import ReversibleStep, ManualEditStep, UserInputStep from ..libs.util.telemetry import capture_event from .sdk import ContinueSDK @@ -47,10 +49,11 @@ class Autopilot(ContinueBaseModel): history: History = History.from_empty() context: Context = Context() full_state: Union[FullState, None] = None - _on_update_callbacks: List[Callable[[FullState], None]] = [] - + context_manager: Union[ContextManager, None] = None continue_sdk: ContinueSDK = None + _on_update_callbacks: List[Callable[[FullState], None]] = [] + _active: bool = False _should_halt: bool = False _main_user_input_queue: List[str] = [] @@ -62,6 +65,14 @@ class Autopilot(ContinueBaseModel): async def create(cls, policy: Policy, ide: AbstractIdeProtocolServer, full_state: FullState) -> "Autopilot": autopilot = cls(ide=ide, policy=policy) autopilot.continue_sdk = await ContinueSDK.create(autopilot) + + # Load documents into the search index + autopilot.context_manager = ContextManager( + autopilot.continue_sdk.config.context_providers + [ + HighlightedCodeContextProvider(ide=ide) + ]) + await autopilot.context_manager.load_index() + return autopilot class Config: @@ -75,15 +86,16 @@ class Autopilot(ContinueBaseModel): values['history'] = full_state.history return values - def get_full_state(self) -> FullState: + async def get_full_state(self) -> FullState: full_state = FullState( history=self.history, active=self._active, user_input_queue=self._main_user_input_queue, default_model=self.continue_sdk.config.default_model, - highlighted_ranges=self._highlighted_ranges, slash_commands=self.get_available_slash_commands(), - adding_highlighted_code=self._adding_highlighted_code, + adding_highlighted_code=self.context_manager.context_providers[ + "code"].adding_highlighted_code, + selected_context_items=await self.context_manager.get_selected_items() ) self.full_state = full_state return full_state @@ -104,8 +116,8 @@ class Autopilot(ContinueBaseModel): self._main_user_input_queue = [] self._active = False - # Also remove all context - self._highlighted_ranges = [] + # Clear context + await self.context_manager.clear_context() await self.update_subscribers() @@ -114,7 +126,7 @@ class Autopilot(ContinueBaseModel): self._on_update_callbacks.append(callback) async def update_subscribers(self): - full_state = self.get_full_state() + full_state = await self.get_full_state() for callback in self._on_update_callbacks: await callback(full_state) @@ -159,81 +171,10 @@ class Autopilot(ContinueBaseModel): step = tb_step.step({"output": output, **tb_step.params}) await self._run_singular_step(step) - _highlighted_ranges: List[HighlightedRangeContext] = [] - _adding_highlighted_code: bool = False - - def _make_sure_is_editing_range(self): - """If none of the highlighted ranges are currently being edited, the first should be selected""" - if len(self._highlighted_ranges) == 0: - return - if not any(map(lambda x: x.editing, self._highlighted_ranges)): - self._highlighted_ranges[0].editing = True - - def _disambiguate_highlighted_ranges(self): - """If any files have the same name, also display their folder name""" - name_status: Dict[str, set] = { - } # basename -> set of full paths with that basename - for rif in self._highlighted_ranges: - basename = os.path.basename(rif.range.filepath) - if basename in name_status: - name_status[basename].add(rif.range.filepath) - else: - name_status[basename] = {rif.range.filepath} - - for rif in self._highlighted_ranges: - basename = os.path.basename(rif.range.filepath) - if len(name_status[basename]) > 1: - rif.display_name = os.path.join( - os.path.basename(os.path.dirname(rif.range.filepath)), basename) - else: - rif.display_name = basename - async def handle_highlighted_code(self, range_in_files: List[RangeInFileWithContents]): - # Filter out rifs from ~/.continue/diffs folder - range_in_files = [ - rif for rif in range_in_files if not os.path.dirname(rif.filepath) == os.path.expanduser("~/.continue/diffs")] - - # Make sure all filepaths are relative to workspace - workspace_path = self.continue_sdk.ide.workspace_directory - - # If not adding highlighted code - if not self._adding_highlighted_code: - if len(self._highlighted_ranges) == 1 and len(range_in_files) <= 1 and (len(range_in_files) == 0 or range_in_files[0].range.start == range_in_files[0].range.end): - # If un-highlighting the range to edit, then remove the range - self._highlighted_ranges = [] - await self.update_subscribers() - elif len(range_in_files) > 0: - # Otherwise, replace the current range with the new one - # This is the first range to be highlighted - self._highlighted_ranges = [HighlightedRangeContext( - range=range_in_files[0], editing=True, pinned=False, display_name=os.path.basename(range_in_files[0].filepath))] - await self.update_subscribers() - return - - # If current range overlaps with any others, delete them and only keep the new range - new_ranges = [] - for i, rif in enumerate(self._highlighted_ranges): - found_overlap = False - for new_rif in range_in_files: - if rif.range.filepath == new_rif.filepath and rif.range.range.overlaps_with(new_rif.range): - found_overlap = True - break - - # Also don't allow multiple ranges in same file with same content. This is useless to the model, and avoids - # the bug where cmd+f causes repeated highlights - if rif.range.filepath == new_rif.filepath and rif.range.contents == new_rif.contents: - found_overlap = True - break - - if not found_overlap: - new_ranges.append(rif) - - self._highlighted_ranges = new_ranges + [HighlightedRangeContext( - range=rif, editing=False, pinned=False, display_name=os.path.basename(rif.filepath) - ) for rif in range_in_files] - - self._make_sure_is_editing_range() - self._disambiguate_highlighted_ranges() + # Add to context manager + await self.context_manager.context_providers["code"].handle_highlighted_code( + range_in_files) await self.update_subscribers() @@ -250,29 +191,16 @@ class Autopilot(ContinueBaseModel): await self.update_subscribers() - async def delete_context_at_indices(self, indices: List[int]): - kept_ranges = [] - for i, rif in enumerate(self._highlighted_ranges): - if i not in indices: - kept_ranges.append(rif) - self._highlighted_ranges = kept_ranges - - self._make_sure_is_editing_range() - + async def delete_context_with_ids(self, ids: List[str]): + await self.context_manager.delete_context_with_ids(ids) await self.update_subscribers() async def toggle_adding_highlighted_code(self): - self._adding_highlighted_code = not self._adding_highlighted_code - await self.update_subscribers() - - async def set_editing_at_indices(self, indices: List[int]): - for i in range(len(self._highlighted_ranges)): - self._highlighted_ranges[i].editing = i in indices + self.context_manager.context_providers["code"].adding_highlighted_code = not self.context_manager.context_providers["code"].adding_highlighted_code await self.update_subscribers() - async def set_pinned_at_indices(self, indices: List[int]): - for i in range(len(self._highlighted_ranges)): - self._highlighted_ranges[i].pinned = i in indices + async def set_editing_at_ids(self, ids: List[str]): + self.context_manager.context_providers["code"].set_editing_at_ids(ids) await self.update_subscribers() async def _run_singular_step(self, step: "Step", is_future_step: bool = False) -> Coroutine[Observation, None, None]: @@ -437,10 +365,6 @@ class Autopilot(ContinueBaseModel): if len(self._main_user_input_queue) > 1: return - # Remove context unless pinned - # self._highlighted_ranges = [ - # hr for hr in self._highlighted_ranges if hr.pinned] - # await self._request_halt() # Just run the step that takes user input, and # then up to the policy to decide how to deal with it. @@ -456,3 +380,7 @@ class Autopilot(ContinueBaseModel): await self._request_halt() await self.reverse_to_index(index) await self.run_from_step(UserInputStep(user_input=user_input)) + + async def select_context_item(self, id: str, query: str): + await self.context_manager.select_context_item(id, query) + await self.update_subscribers() diff --git a/continuedev/src/continuedev/core/config.py b/continuedev/src/continuedev/core/config.py index 54f15143..bb9ca323 100644 --- a/continuedev/src/continuedev/core/config.py +++ b/continuedev/src/continuedev/core/config.py @@ -1,6 +1,7 @@ import json import os from .main import Step +from .context import ContextProvider from pydantic import BaseModel, validator from typing import List, Literal, Optional, Dict, Type, Union import yaml @@ -50,6 +51,8 @@ class ContinueConfig(BaseModel): system_message: Optional[str] = None azure_openai_info: Optional[AzureInfo] = None + context_providers: List[ContextProvider] = [] + # Want to force these to be the slash commands for now @validator('slash_commands', pre=True) def default_slash_commands_validator(cls, v): diff --git a/continuedev/src/continuedev/core/context.py b/continuedev/src/continuedev/core/context.py new file mode 100644 index 00000000..67bba651 --- /dev/null +++ b/continuedev/src/continuedev/core/context.py @@ -0,0 +1,205 @@ + +from abc import abstractmethod +from typing import Dict, List +import meilisearch +from pydantic import BaseModel + + +from .main import ChatMessage, ContextItem, ContextItemDescription, ContextItemId +from ..server.meilisearch_server import check_meilisearch_running + + +SEARCH_INDEX_NAME = "continue_context_items" + + +class ContextProvider(BaseModel): + """ + The ContextProvider class is a plugin that lets you provide new information to the LLM by typing '@'. + When you type '@', the context provider will be asked to populate a list of options. + These options will be updated on each keystroke. + When you hit enter on an option, the context provider will add that item to the autopilot's list of context (which is all stored in the ContextManager object). + """ + + title: str + + selected_items: List[ContextItem] = [] + + async def get_selected_items(self) -> List[ContextItem]: + """ + Returns all of the selected ContextItems. + + Default implementation simply returns self.selected_items. + + Other implementations may add an async processing step. + """ + return self.selected_items + + @abstractmethod + async def provide_context_items(self) -> List[ContextItem]: + """ + Provide documents for search index. This is run on startup. + + This is the only method that must be implemented. + """ + + async def get_chat_messages(self) -> List[ChatMessage]: + """ + Returns all of the chat messages for the context provider. + + Default implementation has a string template. + """ + return [ChatMessage(role="user", content=f"{item.description.name}: {item.description.description}\n\n{item.content}", summary=item.description.description) for item in await self.get_selected_items()] + + async def get_item(self, id: ContextItemId, query: str, search_client: meilisearch.Client) -> ContextItem: + """ + Returns the ContextItem with the given id. + + Default implementation uses the search index to get the item. + """ + result = search_client.index( + SEARCH_INDEX_NAME).get_document(id.to_string()) + return ContextItem( + description=ContextItemDescription( + name=result.name, + description=result.description, + id=id + ), + content=result.content + ) + + async def delete_context_with_ids(self, ids: List[ContextItemId]): + """ + Deletes the ContextItems with the given IDs, lets ContextProviders recalculate. + + Default implementation simply deletes those with the given ids. + """ + id_strings = {id.to_string() for id in ids} + self.selected_items = list( + filter(lambda item: item.description.id.to_string() not in id_strings, self.selected_items)) + + async def clear_context(self): + """ + Clears all context. + + Default implementation simply clears the selected items. + """ + self.selected_items = [] + + async def add_context_item(self, id: ContextItemId, query: str, search_client: meilisearch.Client): + """ + Adds the given ContextItem to the list of ContextItems. + + Default implementation simply appends the item, not allowing duplicates. + + This method also allows you not to have to load all of the information until an item is selected. + """ + + # Don't add duplicate context + for item in self.selected_items: + if item.description.id.item_id == id.item_id: + return + + new_item = await self.get_item(id, query, search_client) + self.selected_items.append(new_item) + + +class ContextManager: + """ + The context manager is responsible for storing the context to be passed to the LLM, including + - ContextItems (highlighted code, GitHub Issues, etc.) + - ChatMessages in the history + - System Message + - Functions + + It is responsible for compiling all of this information into a single prompt without exceeding the token limit. + """ + + async def get_selected_items(self) -> List[ContextItem]: + """ + Returns all of the selected ContextItems. + """ + return sum([await provider.get_selected_items() for provider in self.context_providers.values()], []) + + async def get_chat_messages(self) -> List[ChatMessage]: + """ + Returns chat messages from each provider. + """ + return sum([await provider.get_chat_messages() for provider in self.context_providers.values()], []) + + search_client: meilisearch.Client + + def __init__(self, context_providers: List[ContextProvider]): + self.search_client = meilisearch.Client('http://localhost:7700') + + # If meilisearch isn't running, don't use any ContextProviders that might depend on it + if not check_meilisearch_running(): + context_providers = list( + filter(lambda cp: cp.title == "code", context_providers)) + + self.context_providers = { + prov.title: prov for prov in context_providers} + self.provider_titles = { + provider.title for provider in context_providers} + + async def load_index(self): + for _, provider in self.context_providers.items(): + context_items = await provider.provide_context_items() + documents = [ + { + "id": item.description.id.to_string(), + "name": item.description.name, + "description": item.description.description, + "content": item.content + } + for item in context_items + ] + if len(documents) > 0: + self.search_client.index( + SEARCH_INDEX_NAME).add_documents(documents) + + # def compile_chat_messages(self, max_tokens: int) -> List[Dict]: + # """ + # Compiles the chat prompt into a single string. + # """ + # return compile_chat_messages(self.model, self.chat_history, max_tokens, self.prompt, self.functions, self.system_message) + + async def select_context_item(self, id: str, query: str): + """ + Selects the ContextItem with the given id. + """ + id: ContextItemId = ContextItemId.from_string(id) + if id.provider_title not in self.provider_titles: + raise ValueError( + f"Context provider with title {id.provider_title} not found") + + await self.context_providers[id.provider_title].add_context_item(id, query, self.search_client) + + async def delete_context_with_ids(self, ids: List[str]): + """ + Deletes the ContextItems with the given IDs, lets ContextProviders recalculate. + """ + + # Group by provider title + provider_title_to_ids: Dict[str, List[ContextItemId]] = {} + for id in ids: + id: ContextItemId = ContextItemId.from_string(id) + if id.provider_title not in provider_title_to_ids: + provider_title_to_ids[id.provider_title] = [] + provider_title_to_ids[id.provider_title].append(id) + + # Recalculate context for each updated provider + for provider_title, ids in provider_title_to_ids.items(): + await self.context_providers[provider_title].delete_context_with_ids(ids) + + async def clear_context(self): + """ + Clears all context. + """ + for provider in self.context_providers.values(): + await self.context_providers[provider.title].clear_context() + + +""" +Should define "ArgsTransformer" and "PromptTransformer" classes for the different LLMs. A standard way for them to ingest the +same format of prompts so you don't have to redo all of this logic. +""" diff --git a/continuedev/src/continuedev/core/context_manager.py b/continuedev/src/continuedev/core/context_manager.py deleted file mode 100644 index 37905535..00000000 --- a/continuedev/src/continuedev/core/context_manager.py +++ /dev/null @@ -1,119 +0,0 @@ - -from abc import ABC, abstractmethod, abstractproperty -from ast import List -from pydantic import BaseModel - -from ..libs.util.count_tokens import compile_chat_messages - - -class ContextItemDescription(BaseModel): - """ - A ContextItemDescription is a description of a ContextItem that is displayed to the user when they type '@'. - - The id can be used to retrieve the ContextItem from the ContextManager. - """ - name: str - description: str - id: str - - -class ContextItem(BaseModel): - """ - A ContextItem is a single item that is stored in the ContextManager. - """ - description: ContextItemDescription - content: str - - -class ContextManager(ABC): - """ - The context manager is responsible for storing the context to be passed to the LLM, including - - ContextItems (highlighted code, GitHub Issues, etc.) - - ChatMessages in the history - - System Message - - Functions - - It is responsible for compiling all of this information into a single prompt without exceeding the token limit. - """ - - def compile_chat_messages(self, max_tokens: int) -> List[Dict]: - """ - Compiles the chat prompt into a single string. - """ - return compile_chat_messages(self.model, self.chat_history, max_tokens, self.prompt, self.functions, self.system_message) - - -""" -Should define "ArgsTransformer" and "PromptTransformer" classes for the different LLMs. A standard way for them to ingest the -same format of prompts so you don't have to redo all of this logic. -""" - - -class ContextProvider(ABC): - """ - The ContextProvider class is a plugin that lets you provide new information to the LLM by typing '@'. - When you type '@', the context provider will be asked to populate a list of options. - These options will be updated on each keystroke. - When you hit enter on an option, the context provider will add that item to the autopilot's list of context (which is all stored in the ContextManager object). - """ - - title: str - - @abstractmethod - async def load(self): - """ - Loads the ContextProvider, possibly reading persisted data from disk. This will be called on startup. - """ - - @abstractmethod - async def save(self): - """ - Saves the ContextProvider, possibly writing persisted data to disk. This will be called upon cache refresh. - """ - - @abstractmethod - async def refresh_cache(self): - """ - Refreshes the cache of items. This will be called on startup and periodically. - """ - - @abstractmethod - async def get_item_descriptions(self, query: str) -> List[ContextItemDescription]: - """ - Returns a list of options that should be displayed to the user. - """ - - @abstractmethod - async def get_item(self, id: str) -> ContextItem: - """ - Returns the ContextItem with the given id. This allows you not to have to load all of the information until an item is selected. - """ - - @abstractmethod - async def should_refresh(self) -> bool: - """ - Returns whether the ContextProvider should be refreshed. - - For example, embeddings might need to be recalculated after commits, - or GitHub issues might need to be refreshed after a new issue is created. - - This method will be called every startup? Every once in a while? Every hour? - User defined? Maybe just have a schedule instead of this method. - """ - - -class GitHubIssuesContextProvider(ContextProvider): - """ - The GitHubIssuesContextProvider is a ContextProvider that allows you to search GitHub issues in a repo. - """ - - title = "issues" - - def __init__(self, repo: str): - self.repo = repo - - async def get_item_descriptions(self, query: str) -> List[ContextItemDescription]: - pass - - async def get_item(self, id: str) -> ContextItem: - pass diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py index 50d01f8d..6c6adccc 100644 --- a/continuedev/src/continuedev/core/main.py +++ b/continuedev/src/continuedev/core/main.py @@ -1,12 +1,11 @@ import json -from textwrap import dedent -from typing import Callable, Coroutine, Dict, Generator, List, Literal, Tuple, Union +from typing import Coroutine, Dict, List, Literal, Union +from pydantic.schema import schema + -from ..models.filesystem import RangeInFileWithContents from ..models.main import ContinueBaseModel -from pydantic import validator +from pydantic import BaseModel, validator from .observation import Observation -from pydantic.schema import schema ChatMessageRole = Literal["assistant", "user", "system", "function"] @@ -201,12 +200,48 @@ class SlashCommandDescription(ContinueBaseModel): description: str -class HighlightedRangeContext(ContinueBaseModel): - """Context for a highlighted range""" - range: RangeInFileWithContents - editing: bool - pinned: bool - display_name: str +class ContextItemId(BaseModel): + """ + A ContextItemId is a unique identifier for a ContextItem. + """ + provider_title: str + item_id: str + + def to_string(self) -> str: + return f"{self.provider_title}-{self.item_id}" + + @staticmethod + def from_string(string: str) -> 'ContextItemId': + provider_title, item_id = string.split('-') + return ContextItemId(provider_title=provider_title, item_id=item_id) + + +class ContextItemDescription(BaseModel): + """ + A ContextItemDescription is a description of a ContextItem that is displayed to the user when they type '@'. + + The id can be used to retrieve the ContextItem from the ContextManager. + """ + name: str + description: str + id: ContextItemId + + +class ContextItem(BaseModel): + """ + A ContextItem is a single item that is stored in the ContextManager. + """ + description: ContextItemDescription + content: str + + @validator('content', pre=True) + def content_must_be_string(cls, v): + if v is None: + return '' + return v + + editing: bool = False + editable: bool = False class FullState(ContinueBaseModel): @@ -215,9 +250,9 @@ class FullState(ContinueBaseModel): active: bool user_input_queue: List[str] default_model: str - highlighted_ranges: List[HighlightedRangeContext] slash_commands: List[SlashCommandDescription] adding_highlighted_code: bool + selected_context_items: List[ContextItem] class ContinueSDK: diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py index 4100efa6..59f33707 100644 --- a/continuedev/src/continuedev/core/sdk.py +++ b/continuedev/src/continuedev/core/sdk.py @@ -3,8 +3,10 @@ from functools import cached_property from typing import Coroutine, Dict, Union import os + from ..steps.core.core import DefaultModelEditCodeStep from ..models.main import Range +from .context import ContextItem from .abstract_sdk import AbstractContinueSDK from .config import ContinueConfig, load_config, load_global_config, update_global_config from ..models.filesystem_edit import FileEdit, FileSystemEdit, AddFile, DeleteFile, AddDirectory, DeleteDirectory @@ -289,28 +291,13 @@ class ContinueSDK(AbstractContinueSDK): async def get_chat_context(self) -> List[ChatMessage]: history_context = self.history.to_chat_history() - highlighted_code = [ - hr.range for hr in self.__autopilot._highlighted_ranges] - - preface = "The following code is highlighted" - - # If no higlighted ranges, use first file as context - if len(highlighted_code) == 0: - preface = "The following file is open" - visible_files = await self.ide.getVisibleFiles() - if len(visible_files) > 0: - content = await self.ide.readFile(visible_files[0]) - highlighted_code = [ - RangeInFileWithContents.from_entire_file(visible_files[0], content)] - - for rif in highlighted_code: - msg = ChatMessage(content=f"{preface} ({rif.filepath}):\n```\n{rif.contents}\n```", - role="user", summary=f"{preface}: {rif.filepath}") - - # Don't insert after latest user message or function call - i = -1 - if len(history_context) > 0 and (history_context[i].role == "user" or history_context[i].role == "function"): - i -= 1 + + context_messages: List[ChatMessage] = await self.__autopilot.context_manager.get_chat_messages() + + # Insert at the end, but don't insert after latest user message or function call + i = -2 if (len(history_context) > 0 and ( + history_context[-1].role == "user" or history_context[-1].role == "function")) else -1 + for msg in context_messages: history_context.insert(i, msg) return history_context diff --git a/continuedev/src/continuedev/libs/context_providers/highlighted_code_context_provider.py b/continuedev/src/continuedev/libs/context_providers/highlighted_code_context_provider.py new file mode 100644 index 00000000..23d4fc86 --- /dev/null +++ b/continuedev/src/continuedev/libs/context_providers/highlighted_code_context_provider.py @@ -0,0 +1,191 @@ +import os +from typing import Any, Dict, List + +import meilisearch +from ...core.main import ChatMessage +from ...models.filesystem import RangeInFile, RangeInFileWithContents +from ...core.context import ContextItem, ContextItemDescription, ContextItemId +from pydantic import BaseModel + + +class HighlightedRangeContextItem(BaseModel): + rif: RangeInFileWithContents + item: ContextItem + + +class HighlightedCodeContextProvider(BaseModel): + """ + The ContextProvider class is a plugin that lets you provide new information to the LLM by typing '@'. + When you type '@', the context provider will be asked to populate a list of options. + These options will be updated on each keystroke. + When you hit enter on an option, the context provider will add that item to the autopilot's list of context (which is all stored in the ContextManager object). + """ + + title = "code" + + ide: Any # IdeProtocolServer + + highlighted_ranges: List[HighlightedRangeContextItem] = [] + adding_highlighted_code: bool = False + + should_get_fallback_context_item: bool = True + last_added_fallback: bool = False + + async def _get_fallback_context_item(self) -> HighlightedRangeContextItem: + if not self.should_get_fallback_context_item: + return None + + visible_files = await self.ide.getVisibleFiles() + if len(visible_files) > 0: + content = await self.ide.readFile(visible_files[0]) + rif = RangeInFileWithContents.from_entire_file( + visible_files[0], content) + + item = self._rif_to_context_item(rif, 0, True) + item.description.name = self._rif_to_name( + rif, show_line_nums=False) + + self.last_added_fallback = True + return HighlightedRangeContextItem(rif=rif, item=item) + + return None + + async def get_selected_items(self) -> List[ContextItem]: + items = [hr.item for hr in self.highlighted_ranges] + + if len(items) == 0 and (fallback_item := await self._get_fallback_context_item()): + items = [fallback_item.item] + + return items + + async def get_chat_messages(self) -> List[ContextItem]: + ranges = self.highlighted_ranges + if len(ranges) == 0 and (fallback_item := await self._get_fallback_context_item()): + ranges = [fallback_item] + + return [ChatMessage( + role="user", + content=f"Code in this file is highlighted ({r.rif.filepath}):\n```\n{r.rif.contents}\n```", + summary=f"Code in this file is highlighted: {r.rif.filepath}" + ) for r in ranges] + + def _make_sure_is_editing_range(self): + """If none of the highlighted ranges are currently being edited, the first should be selected""" + if len(self.highlighted_ranges) == 0: + return + if not any(map(lambda x: x.item.editing, self.highlighted_ranges)): + self.highlighted_ranges[0].item.editing = True + + def _disambiguate_highlighted_ranges(self): + """If any files have the same name, also display their folder name""" + name_status: Dict[str, set] = { + } # basename -> set of full paths with that basename + for hr in self.highlighted_ranges: + basename = os.path.basename(hr.rif.filepath) + if basename in name_status: + name_status[basename].add(hr.rif.filepath) + else: + name_status[basename] = {hr.rif.filepath} + + for hr in self.highlighted_ranges: + if len(name_status[basename]) > 1: + hr.item.description.name = self._rif_to_name(hr.rif, display_filename=os.path.join( + os.path.basename(os.path.dirname(hr.rif.filepath)), basename)) + else: + hr.item.description.name = self._rif_to_name( + hr.rif, display_filename=basename) + + async def provide_context_items(self) -> List[ContextItem]: + return [] + + async def delete_context_with_ids(self, ids: List[ContextItemId]) -> List[ContextItem]: + indices_to_delete = [ + int(id.item_id) for id in ids + ] + + kept_ranges = [] + for i, hr in enumerate(self.highlighted_ranges): + if i not in indices_to_delete: + kept_ranges.append(hr) + self.highlighted_ranges = kept_ranges + + self._make_sure_is_editing_range() + + if len(self.highlighted_ranges) == 0 and self.last_added_fallback: + self.should_get_fallback_context_item = False + + return [hr.item for hr in self.highlighted_ranges] + + def _rif_to_name(self, rif: RangeInFileWithContents, display_filename: str = None, show_line_nums: bool = True) -> str: + line_nums = f" ({rif.range.start.line + 1}-{rif.range.end.line + 1})" if show_line_nums else "" + return f"{display_filename or os.path.basename(rif.filepath)}{line_nums}" + + def _rif_to_context_item(self, rif: RangeInFileWithContents, idx: int, editing: bool) -> ContextItem: + return ContextItem( + description=ContextItemDescription( + name=self._rif_to_name(rif), + description=rif.filepath, + id=ContextItemId( + provider_title=self.title, + item_id=str(idx) + ) + ), + content=rif.contents, + editing=editing, + editable=True + ) + + async def handle_highlighted_code(self, range_in_files: List[RangeInFileWithContents]): + self.should_get_fallback_context_item = True + self.last_added_fallback = False + + # Filter out rifs from ~/.continue/diffs folder + range_in_files = [ + rif for rif in range_in_files if not os.path.dirname(rif.filepath) == os.path.expanduser("~/.continue/diffs")] + + # If not adding highlighted code + if not self.adding_highlighted_code: + if len(self.highlighted_ranges) == 1 and len(range_in_files) <= 1 and (len(range_in_files) == 0 or range_in_files[0].range.start == range_in_files[0].range.end): + # If un-highlighting the range to edit, then remove the range + self.highlighted_ranges = [] + elif len(range_in_files) > 0: + # Otherwise, replace the current range with the new one + # This is the first range to be highlighted + self.highlighted_ranges = [ + HighlightedRangeContextItem( + rif=range_in_files[0], + item=self._rif_to_context_item(range_in_files[0], 0, True))] + + return + + # If current range overlaps with any others, delete them and only keep the new range + new_ranges = [] + for i, hr in enumerate(self.highlighted_ranges): + found_overlap = False + for new_rif in range_in_files: + if hr.rif.filepath == new_rif.filepath and hr.rif.range.overlaps_with(new_rif.range): + found_overlap = True + break + + # Also don't allow multiple ranges in same file with same content. This is useless to the model, and avoids + # the bug where cmd+f causes repeated highlights + if hr.rif.filepath == new_rif.filepath and hr.rif.contents == new_rif.contents: + found_overlap = True + break + + if not found_overlap: + new_ranges.append(HighlightedRangeContextItem(rif=hr.rif, item=self._rif_to_context_item( + hr.rif, len(new_ranges), False))) + + self.highlighted_ranges = new_ranges + [HighlightedRangeContextItem(rif=rif, item=self._rif_to_context_item( + rif, len(new_ranges) + idx, False)) for idx, rif in enumerate(range_in_files)] + + self._make_sure_is_editing_range() + self._disambiguate_highlighted_ranges() + + async def set_editing_at_ids(self, ids: List[str]): + for hr in self.highlighted_ranges: + hr.item.editing = hr.item.description.id.to_string() in ids + + async def add_context_item(self, id: ContextItemId, query: str, search_client: meilisearch.Client, prev: List[ContextItem] = None) -> List[ContextItem]: + raise NotImplementedError() diff --git a/continuedev/src/continuedev/libs/util/paths.py b/continuedev/src/continuedev/libs/util/paths.py index fddef887..d6ce13b3 100644 --- a/continuedev/src/continuedev/libs/util/paths.py +++ b/continuedev/src/continuedev/libs/util/paths.py @@ -2,16 +2,26 @@ import os from ..constants.main import CONTINUE_SESSIONS_FOLDER, CONTINUE_GLOBAL_FOLDER, CONTINUE_SERVER_FOLDER -def getGlobalFolderPath(): - return os.path.join(os.path.expanduser("~"), CONTINUE_GLOBAL_FOLDER) +def getGlobalFolderPath(): + path = os.path.join(os.path.expanduser("~"), CONTINUE_GLOBAL_FOLDER) + os.makedirs(path, exist_ok=True) + return path def getSessionsFolderPath(): - return os.path.join(getGlobalFolderPath(), CONTINUE_SESSIONS_FOLDER) + path = os.path.join(getGlobalFolderPath(), CONTINUE_SESSIONS_FOLDER) + os.makedirs(path, exist_ok=True) + return path + def getServerFolderPath(): - return os.path.join(getGlobalFolderPath(), CONTINUE_SERVER_FOLDER) + path = os.path.join(getGlobalFolderPath(), CONTINUE_SERVER_FOLDER) + os.makedirs(path, exist_ok=True) + return path + def getSessionFilePath(session_id: str): - return os.path.join(getSessionsFolderPath(), f"{session_id}.json") \ No newline at end of file + path = os.path.join(getSessionsFolderPath(), f"{session_id}.json") + os.makedirs(os.path.dirname(path), exist_ok=True) + return path diff --git a/continuedev/src/continuedev/models/generate_json_schema.py b/continuedev/src/continuedev/models/generate_json_schema.py index 6cebf429..06614984 100644 --- a/continuedev/src/continuedev/models/generate_json_schema.py +++ b/continuedev/src/continuedev/models/generate_json_schema.py @@ -2,6 +2,7 @@ from .main import * from .filesystem import RangeInFile, FileEdit from .filesystem_edit import FileEditWithFullContents from ..core.main import History, HistoryNode, FullState +from ..core.context import ContextItem from pydantic import schema_json_of import os @@ -13,6 +14,8 @@ MODELS_TO_GENERATE = [ FileEditWithFullContents ] + [ History, HistoryNode, FullState +] + [ + ContextItem ] RENAMES = { diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py index ae57c0b6..36b2f3fa 100644 --- a/continuedev/src/continuedev/server/gui.py +++ b/continuedev/src/continuedev/server/gui.py @@ -91,25 +91,19 @@ class GUIProtocolServer(AbstractGUIProtocolServer): self.on_clear_history() elif message_type == "delete_at_index": self.on_delete_at_index(data["index"]) - elif message_type == "delete_context_at_indices": - self.on_delete_context_at_indices(data["indices"]) + elif message_type == "delete_context_with_ids": + self.on_delete_context_with_ids(data["ids"]) elif message_type == "toggle_adding_highlighted_code": self.on_toggle_adding_highlighted_code() elif message_type == "set_editing_at_indices": self.on_set_editing_at_indices(data["indices"]) - elif message_type == "set_pinned_at_indices": - self.on_set_pinned_at_indices(data["indices"]) elif message_type == "show_logs_at_index": self.on_show_logs_at_index(data["index"]) + elif message_type == "select_context_item": + self.select_context_item(data["id"], data["query"]) except Exception as e: print(e) - async def send_state_update(self): - state = self.session.autopilot.get_full_state().dict() - await self._send_json("state_update", { - "state": state - }) - def on_main_input(self, input: str): # Do something with user input create_async_task(self.session.autopilot.accept_user_input( @@ -144,10 +138,10 @@ class GUIProtocolServer(AbstractGUIProtocolServer): create_async_task(self.session.autopilot.delete_at_index( index), self.session.autopilot.continue_sdk.ide.unique_id) - def on_delete_context_at_indices(self, indices: List[int]): + def on_delete_context_with_ids(self, ids: List[str]): create_async_task( - self.session.autopilot.delete_context_at_indices( - indices), self.session.autopilot.continue_sdk.ide.unique_id + self.session.autopilot.delete_context_with_ids( + ids), self.session.autopilot.continue_sdk.ide.unique_id ) def on_toggle_adding_highlighted_code(self): @@ -162,18 +156,17 @@ class GUIProtocolServer(AbstractGUIProtocolServer): indices), self.session.autopilot.continue_sdk.ide.unique_id ) - def on_set_pinned_at_indices(self, indices: List[int]): - create_async_task( - self.session.autopilot.set_pinned_at_indices( - indices), self.session.autopilot.continue_sdk.ide.unique_id - ) - def on_show_logs_at_index(self, index: int): name = f"continue_logs.txt" logs = "\n\n############################################\n\n".join( ["This is a log of the exact prompt/completion pairs sent/received from the LLM during this step"] + self.session.autopilot.continue_sdk.history.timeline[index].logs) create_async_task( - self.session.autopilot.ide.showVirtualFile(name, logs)) + self.session.autopilot.ide.showVirtualFile(name, logs), self.session.autopilot.continue_sdk.ide.unique_id) + + def select_context_item(self, id: str, query: str): + """Called when user selects an item from the dropdown""" + create_async_task( + self.session.autopilot.select_context_item(id, query), self.session.autopilot.continue_sdk.ide.unique_id) @router.websocket("/ws") @@ -188,7 +181,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_state_update() + await protocol.session.autopilot.update_subscribers() while AppStatus.should_exit is False: message = await websocket.receive_text() @@ -214,5 +207,5 @@ async def websocket_endpoint(websocket: WebSocket, session: Session = Depends(we if websocket.client_state != WebSocketState.DISCONNECTED: await websocket.close() - session_manager.persist_session(session.session_id) + await session_manager.persist_session(session.session_id) session_manager.remove_session(session.session_id) diff --git a/continuedev/src/continuedev/server/gui_protocol.py b/continuedev/src/continuedev/server/gui_protocol.py index 9766fcd0..fb230216 100644 --- a/continuedev/src/continuedev/server/gui_protocol.py +++ b/continuedev/src/continuedev/server/gui_protocol.py @@ -1,6 +1,8 @@ from typing import Any, Dict, List from abc import ABC, abstractmethod +from ..core.context import ContextItem + class AbstractGUIProtocolServer(ABC): @abstractmethod @@ -23,10 +25,6 @@ class AbstractGUIProtocolServer(ABC): def on_step_user_input(self, input: str, index: int): """Called when the user inputs a step""" - @abstractmethod - async def send_state_update(self, state: dict): - """Send a state update to the client""" - @abstractmethod def on_retry_at_index(self, index: int): """Called when the user requests a retry at a previous index""" @@ -42,3 +40,7 @@ class AbstractGUIProtocolServer(ABC): @abstractmethod def on_delete_at_index(self, index: int): """Called when the user requests to delete a step at a given index""" + + @abstractmethod + def select_context_item(self, id: str, query: str): + """Called when user selects an item from the dropdown""" diff --git a/continuedev/src/continuedev/server/main.py b/continuedev/src/continuedev/server/main.py index 42dc0cc1..7ee64041 100644 --- a/continuedev/src/continuedev/server/main.py +++ b/continuedev/src/continuedev/server/main.py @@ -1,15 +1,20 @@ +import asyncio +import subprocess import time +import meilisearch import psutil import os from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware -from .ide import router as ide_router -from .gui import router as gui_router -from .session_manager import session_manager import atexit import uvicorn import argparse +from .ide import router as ide_router +from .gui import router as gui_router +from .session_manager import session_manager +from .meilisearch_server import start_meilisearch + app = FastAPI() app.include_router(ide_router) @@ -41,15 +46,20 @@ args = parser.parse_args() # log_file = open('output.log', 'a') # sys.stdout = log_file - def run_server(): uvicorn.run(app, host="0.0.0.0", port=args.port) -def cleanup(): +async def cleanup_coroutine(): print("Cleaning up sessions") for session_id in session_manager.sessions: - session_manager.persist_session(session_id) + await session_manager.persist_session(session_id) + + +def cleanup(): + loop = asyncio.new_event_loop() + loop.run_until_complete(cleanup_coroutine()) + loop.close() def cpu_usage_report(): @@ -77,6 +87,12 @@ if __name__ == "__main__": # cpu_thread = threading.Thread(target=cpu_usage_loop) # cpu_thread.start() + try: + start_meilisearch() + except Exception as e: + print("Failed to start MeiliSearch") + print(e) + run_server() except Exception as e: cleanup() diff --git a/continuedev/src/continuedev/server/meilisearch_server.py b/continuedev/src/continuedev/server/meilisearch_server.py new file mode 100644 index 00000000..419f081f --- /dev/null +++ b/continuedev/src/continuedev/server/meilisearch_server.py @@ -0,0 +1,56 @@ +import os +import subprocess + +import meilisearch +from ..libs.util.paths import getServerFolderPath + + +def check_meilisearch_installed() -> bool: + """ + Checks if MeiliSearch is installed. + """ + + serverPath = getServerFolderPath() + meilisearchPath = os.path.join(serverPath, "meilisearch") + + return os.path.exists(meilisearchPath) + + +def check_meilisearch_running() -> bool: + """ + Checks if MeiliSearch is running. + """ + + try: + client = meilisearch.Client('http://localhost:7700') + resp = client.health() + if resp["status"] != "available": + return False + return True + except Exception: + return False + + +def start_meilisearch(): + """ + Starts the MeiliSearch server, wait for it. + """ + + # Doesn't work on windows for now + if not os.name == "posix": + return + + serverPath = getServerFolderPath() + + # Check if MeiliSearch is installed + if not check_meilisearch_installed(): + # Download MeiliSearch + print("Downloading MeiliSearch...") + subprocess.run( + f"curl -L https://install.meilisearch.com | sh", shell=True, check=True, cwd=serverPath) + + # Check if MeiliSearch is running + if not check_meilisearch_running(): + print("Starting MeiliSearch...") + subprocess.Popen(["./meilisearch"], cwd=serverPath, stdout=subprocess.DEVNULL, + stderr=subprocess.STDOUT, close_fds=True, start_new_session=True) diff --git a/continuedev/src/continuedev/server/session_manager.py b/continuedev/src/continuedev/server/session_manager.py index 90172a4e..96daf92c 100644 --- a/continuedev/src/continuedev/server/session_manager.py +++ b/continuedev/src/continuedev/server/session_manager.py @@ -74,7 +74,7 @@ class SessionManager: async def on_update(state: FullState): await session_manager.send_ws_data(session_id, "state_update", { - "state": autopilot.get_full_state().dict() + "state": state.dict() }) autopilot.on_update(on_update) @@ -84,9 +84,9 @@ class SessionManager: def remove_session(self, session_id: str): del self.sessions[session_id] - def persist_session(self, session_id: str): + async def persist_session(self, session_id: str): """Save the session's FullState as a json file""" - full_state = self.sessions[session_id].autopilot.get_full_state() + full_state = await self.sessions[session_id].autopilot.get_full_state() if not os.path.exists(getSessionsFolderPath()): os.mkdir(getSessionsFolderPath()) with open(getSessionFilePath(session_id), "w") as f: diff --git a/extension/react-app/package-lock.json b/extension/react-app/package-lock.json index 13e02e86..fa7834f1 100644 --- a/extension/react-app/package-lock.json +++ b/extension/react-app/package-lock.json @@ -13,6 +13,7 @@ "@types/vscode-webview": "^1.57.1", "@uiw/react-markdown-preview": "^4.1.13", "downshift": "^7.6.0", + "meilisearch": "^0.33.0", "posthog-js": "^1.58.0", "prismjs": "^1.29.0", "react": "^18.2.0", @@ -1423,6 +1424,14 @@ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz", "integrity": "sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g==" }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/css-color-keywords": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", @@ -2500,6 +2509,14 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/meilisearch": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.33.0.tgz", + "integrity": "sha512-bYPb9WyITnJfzf92e7QFK8Rc50DmshFWxypXCs3ILlpNh8pT15A7KSu9Xgnnk/K3G/4vb3wkxxtFS4sxNkWB8w==", + "dependencies": { + "cross-fetch": "^3.1.6" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -3092,6 +3109,25 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", @@ -4115,6 +4151,11 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -4423,6 +4464,20 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -5325,6 +5380,14 @@ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz", "integrity": "sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g==" }, + "cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "requires": { + "node-fetch": "^2.6.12" + } + }, "css-color-keywords": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", @@ -6098,6 +6161,14 @@ "@types/mdast": "^3.0.0" } }, + "meilisearch": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.33.0.tgz", + "integrity": "sha512-bYPb9WyITnJfzf92e7QFK8Rc50DmshFWxypXCs3ILlpNh8pT15A7KSu9Xgnnk/K3G/4vb3wkxxtFS4sxNkWB8w==", + "requires": { + "cross-fetch": "^3.1.6" + } + }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -6434,6 +6505,14 @@ "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "dev": true }, + "node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, "node-releases": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", @@ -7129,6 +7208,11 @@ "is-number": "^7.0.0" } }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -7315,6 +7399,20 @@ "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==" }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/extension/react-app/package.json b/extension/react-app/package.json index 704f520a..e5f5a329 100644 --- a/extension/react-app/package.json +++ b/extension/react-app/package.json @@ -14,6 +14,7 @@ "@types/vscode-webview": "^1.57.1", "@uiw/react-markdown-preview": "^4.1.13", "downshift": "^7.6.0", + "meilisearch": "^0.33.0", "posthog-js": "^1.58.0", "prismjs": "^1.29.0", "react": "^18.2.0", diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx index f327e3a3..22a6d000 100644 --- a/extension/react-app/src/components/ComboBox.tsx +++ b/extension/react-app/src/components/ComboBox.tsx @@ -1,4 +1,9 @@ -import React, { useEffect, useImperativeHandle, useState } from "react"; +import React, { + useContext, + useEffect, + useImperativeHandle, + useState, +} from "react"; import { useCombobox } from "downshift"; import styled from "styled-components"; import { @@ -8,13 +13,15 @@ import { vscBackground, vscForeground, } from "."; -import CodeBlock from "./CodeBlock"; import PillButton from "./PillButton"; import HeaderButtonWithText from "./HeaderButtonWithText"; import { DocumentPlus } from "@styled-icons/heroicons-outline"; -import { HighlightedRangeContext } from "../../../schema/FullState"; +import { ContextItem } from "../../../schema/FullState"; import { postVscMessage } from "../vscode"; -import { getMetaKeyLabel } from "../util"; +import { GUIClientContext } from "../App"; +import { MeiliSearch } from "meilisearch"; + +const SEARCH_INDEX_NAME = "continue_context_items"; // #region styled components const mainInputFontSize = 13; @@ -64,14 +71,14 @@ const Ul = styled.ul<{ hidden: boolean; showAbove: boolean; ulHeightPixels: number; + inputBoxHeight?: string; }>` ${(props) => props.showAbove ? `transform: translateY(-${props.ulHeightPixels + 8}px);` - : `transform: translateY(${2 * mainInputFontSize}px);`} + : `transform: translateY(${5 * mainInputFontSize}px);`} position: absolute; background: ${vscBackground}; - background-color: ${secondaryDark}; color: ${vscForeground}; max-height: ${UlMaxHeight}px; width: calc(100% - 16px); @@ -80,15 +87,9 @@ const Ul = styled.ul<{ padding: 0; ${({ hidden }) => hidden && "display: none;"} border-radius: ${defaultBorderRadius}; - outline: 0.5px solid gray; + outline: 1px solid ${lightGray}; z-index: 2; - // Get rid of scrollbar and its padding - scrollbar-width: none; -ms-overflow-style: none; - &::-webkit-scrollbar { - width: 0px; - background: transparent; /* make scrollbar transparent */ - } `; const Li = styled.li<{ @@ -96,49 +97,90 @@ const Li = styled.li<{ selected: boolean; isLastItem: boolean; }>` - background-color: ${secondaryDark}; - ${({ highlighted }) => highlighted && "background: #ff000066;"} + background-color: ${({ highlighted }) => + highlighted ? lightGray : secondaryDark}; + ${({ highlighted }) => highlighted && `background: ${vscBackground};`} ${({ selected }) => selected && "font-weight: bold;"} padding: 0.5rem 0.75rem; display: flex; flex-direction: column; ${({ isLastItem }) => isLastItem && "border-bottom: 1px solid gray;"} - border-top: 1px solid gray; + /* border-top: 1px solid gray; */ cursor: pointer; `; // #endregion interface ComboBoxProps { - items: { name: string; description: string }[]; + items: { name: string; description: string; id?: string }[]; onInputValueChange: (inputValue: string) => void; disabled?: boolean; onEnter: (e: React.KeyboardEvent) => void; - highlightedCodeSections: HighlightedRangeContext[]; - deleteContextItems: (indices: number[]) => void; - onTogglePin: () => void; + selectedContextItems: ContextItem[]; onToggleAddContext: () => void; addingHighlightedCode: boolean; } const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { + const searchClient = new MeiliSearch({ host: "http://127.0.0.1:7700" }); + const client = useContext(GUIClientContext); + const [history, setHistory] = React.useState([]); // The position of the current command you are typing now, so the one that will be appended to history once you press enter const [positionInHistory, setPositionInHistory] = React.useState(0); const [items, setItems] = React.useState(props.items); - const [highlightedCodeSections, setHighlightedCodeSections] = React.useState( - props.highlightedCodeSections || [] - ); + const inputRef = React.useRef(null); + const [inputBoxHeight, setInputBoxHeight] = useState( + undefined + ); - useEffect(() => { - setHighlightedCodeSections(props.highlightedCodeSections || []); - }, [props.highlightedCodeSections]); + // Whether the current input follows an '@' and should be treated as context query + const [currentlyInContextQuery, setCurrentlyInContextQuery] = useState(false); const { getInputProps, ...downshiftProps } = useCombobox({ - onInputValueChange({ inputValue }) { + onSelectedItemChange: ({ selectedItem }) => { + if (selectedItem?.id) { + // Get the query from the input value + const segs = downshiftProps.inputValue.split("@"); + const query = segs[segs.length - 1]; + const restOfInput = segs.splice(0, segs.length - 1).join("@"); + + // Tell server the context item was selected + client?.selectContextItem(selectedItem.id, query); + + // Remove the '@' and the context query from the input + if (downshiftProps.inputValue.includes("@")) { + downshiftProps.setInputValue(restOfInput); + } + } + }, + onInputValueChange({ inputValue, highlightedIndex }) { if (!inputValue) return; props.onInputValueChange(inputValue); + + if (inputValue.endsWith("@") || currentlyInContextQuery) { + setCurrentlyInContextQuery(true); + + const segs = inputValue.split("@"); + const providerAndQuery = segs[segs.length - 1]; + const [provider, query] = providerAndQuery.split(" "); + searchClient + .index(SEARCH_INDEX_NAME) + .search(providerAndQuery) + .then((res) => { + setItems( + res.hits.map((hit) => { + return { + name: hit.name, + description: hit.description, + id: hit.id, + }; + }) + ); + }); + return; + } setItems( props.items.filter((item) => item.name.toLowerCase().startsWith(inputValue.toLowerCase()) @@ -151,6 +193,16 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { }, }); + useEffect(() => { + console.log( + "downshiftProps.highlightedIndex", + downshiftProps.highlightedIndex + ); + if (downshiftProps.highlightedIndex < 0) { + downshiftProps.setHighlightedIndex(0); + } + }, [downshiftProps.inputValue]); + useImperativeHandle(ref, () => downshiftProps, [downshiftProps]); const [metaKeyPressed, setMetaKeyPressed] = useState(false); @@ -199,50 +251,22 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { return ( <>
- {/* {highlightedCodeSections.length > 1 && ( - <> - { - props.deleteContextItems( - highlightedCodeSections.map((_, idx) => idx) - ); - }} - > - - - - )} */} - {highlightedCodeSections.map((section, idx) => ( - 4000 && section.editing - ? "Editing such a large range may be slow" - : undefined - } - onlyShowDelete={ - highlightedCodeSections.length <= 1 || section.editing - } - editing={section.editing} - pinned={section.pinned} - index={idx} - key={`${section.display_name}${idx}`} - title={`${section.display_name} (${ - section.range.range.start.line + 1 - }-${section.range.range.end.line + 1})`} - onDelete={() => { - if (props.deleteContextItems) { - props.deleteContextItems([idx]); + {props.selectedContextItems.map((item, idx) => { + return ( + 4000 && item.editing + ? "Editing such a large range may be slow" + : undefined } - setHighlightedCodeSections((prev) => { - const newSections = [...prev]; - newSections.splice(idx, 1); - return newSections; - }); - }} - /> - ))} - {props.highlightedCodeSections.length > 0 && + addingHighlightedCode={props.addingHighlightedCode} + index={idx} + /> + ); + })} + {props.selectedContextItems.length > 0 && (props.addingHighlightedCode ? ( { @@ -275,6 +299,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { target.scrollHeight, 300 ).toString()}px`; + setInputBoxHeight(target.style.height); // setShowContextDropdown(target.value.endsWith("@")); }, @@ -289,6 +314,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { if (event.key === "Enter" && event.shiftKey) { // Prevent Downshift's default 'Enter' behavior. (event.nativeEvent as any).preventDownshiftDefault = true; + setCurrentlyInContextQuery(false); } else if ( event.key === "Enter" && (!downshiftProps.isOpen || items.length === 0) @@ -302,6 +328,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { (event.nativeEvent as any).preventDownshiftDefault = true; if (props.onEnter) props.onEnter(event); + setCurrentlyInContextQuery(false); } else if (event.key === "Tab" && items.length > 0) { downshiftProps.setInputValue(items[0].name); event.preventDefault(); @@ -321,6 +348,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { } downshiftProps.setInputValue(history[positionInHistory - 1]); setPositionInHistory((prev) => prev - 1); + setCurrentlyInContextQuery(false); } else if (event.key === "ArrowDown") { if (positionInHistory < history.length) { downshiftProps.setInputValue(history[positionInHistory + 1]); @@ -328,6 +356,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { setPositionInHistory((prev) => Math.min(prev + 1, history.length) ); + setCurrentlyInContextQuery(false); } }, ref: inputRef, @@ -351,13 +380,14 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { selected={downshiftProps.selectedItem === item} > - {item.name}: {item.description} + {item.name}:{" "} + {item.description} ))}
- {highlightedCodeSections.length === 0 && + {props.selectedContextItems.length === 0 && (downshiftProps.inputValue?.startsWith("/edit") || (focused && metaKeyPressed && diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx index c24dba83..af4263af 100644 --- a/extension/react-app/src/components/PillButton.tsx +++ b/extension/react-app/src/components/PillButton.tsx @@ -1,9 +1,10 @@ -import { useContext, useState } from "react"; +import { useContext, useEffect, useState } from "react"; import styled from "styled-components"; import { StyledTooltip, defaultBorderRadius, secondaryDark, + vscBackground, vscForeground, } from "."; import { @@ -12,6 +13,14 @@ import { ExclamationTriangle, } from "@styled-icons/heroicons-outline"; import { GUIClientContext } from "../App"; +import { useDispatch } from "react-redux"; +import { + setBottomMessage, + setBottomMessageCloseTimeout, +} from "../redux/slices/uiStateSlice"; +import { ContextItem } from "../../../schema/FullState"; +import { ReactMarkdown } from "react-markdown/lib/react-markdown"; +import StyledMarkdownPreview from "./StyledMarkdownPreview"; const Button = styled.button` border: none; @@ -67,19 +76,48 @@ const CircleDiv = styled.div` interface PillButtonProps { onHover?: (arg0: boolean) => void; - onDelete?: () => void; - title: string; - index: number; - editing: boolean; - pinned: boolean; + item: ContextItem; warning?: string; - onlyShowDelete?: boolean; + index: number; + addingHighlightedCode?: boolean; } const PillButton = (props: PillButtonProps) => { const [isHovered, setIsHovered] = useState(false); const client = useContext(GUIClientContext); + const dispatch = useDispatch(); + + useEffect(() => { + if (isHovered) { + dispatch(setBottomMessageCloseTimeout(undefined)); + dispatch( + setBottomMessage( + <> + {props.item.description.name}:{" "} + {props.item.description.description} + + + ) + ); + } else { + dispatch( + setBottomMessageCloseTimeout( + setTimeout(() => { + if (!isHovered) { + dispatch(setBottomMessage(undefined)); + } + }, 2000) + ) + ); + } + }, [isHovered]); + return ( <>
@@ -88,10 +126,8 @@ const PillButton = (props: PillButtonProps) => { position: "relative", borderColor: props.warning ? "red" - : props.editing + : props.item.editing ? "#8800aa" - : props.pinned - ? "#ffff0099" : "transparent", borderWidth: "1px", borderStyle: "solid", @@ -112,10 +148,14 @@ const PillButton = (props: PillButtonProps) => { {isHovered && ( - {props.onlyShowDelete || ( + {props.item.editable && props.addingHighlightedCode && ( { )} - {/* { - client?.setPinnedAtIndices([props.index]); - }} - > - - */} Edit this range @@ -146,33 +177,33 @@ const PillButton = (props: PillButtonProps) => { data-tooltip-id={`delete-${props.index}`} backgroundColor={"#cc000055"} onClick={() => { - if (props.onDelete) { - props.onDelete(); - } + client?.deleteContextWithIds([props.item.description.id]); }} > )} - {props.title} + {props.item.description.name} - {props.editing + {props.item.editing ? "Editing this section (with entire file as context)" : "Edit this section"} Delete {props.warning && ( <> - + - + {props.warning} diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx index bc8665fd..2cfe7ecd 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -18,9 +18,9 @@ import { import { StopCircle } from "@styled-icons/heroicons-solid"; import { HistoryNode } from "../../../schema/HistoryNode"; import HeaderButtonWithText from "./HeaderButtonWithText"; -import MarkdownPreview from "@uiw/react-markdown-preview"; import { getMetaKeyLabel, isMetaEquivalentKeyPressed } from "../util"; import { GUIClientContext } from "../App"; +import StyledMarkdownPreview from "./StyledMarkdownPreview"; interface StepContainerProps { historyNode: HistoryNode; @@ -109,33 +109,6 @@ const GradientBorder = styled.div<{ background-size: 200% 200%; `; -const StyledMarkdownPreview = styled(MarkdownPreview)` - pre { - background-color: ${secondaryDark}; - padding: 1px; - border-radius: ${defaultBorderRadius}; - border: 0.5px solid white; - } - - code { - color: #f78383; - word-wrap: break-word; - border-radius: ${defaultBorderRadius}; - background-color: ${secondaryDark}; - } - - pre > code { - background-color: ${secondaryDark}; - color: ${vscForeground}; - } - - background-color: ${vscBackground}; - font-family: "Lexend", sans-serif; - font-size: 13px; - padding: 8px; - color: ${vscForeground}; -`; - // #endregion function StepContainer(props: StepContainerProps) { diff --git a/extension/react-app/src/components/StyledMarkdownPreview.tsx b/extension/react-app/src/components/StyledMarkdownPreview.tsx new file mode 100644 index 00000000..9c2ecb62 --- /dev/null +++ b/extension/react-app/src/components/StyledMarkdownPreview.tsx @@ -0,0 +1,37 @@ +import styled from "styled-components"; +import { + defaultBorderRadius, + secondaryDark, + vscBackground, + vscForeground, +} from "."; +import MarkdownPreview from "@uiw/react-markdown-preview"; + +const StyledMarkdownPreview = styled(MarkdownPreview)` + pre { + background-color: ${secondaryDark}; + padding: 1px; + border-radius: ${defaultBorderRadius}; + border: 0.5px solid white; + } + + code { + color: #f78383; + word-wrap: break-word; + border-radius: ${defaultBorderRadius}; + background-color: ${secondaryDark}; + } + + pre > code { + background-color: ${secondaryDark}; + color: ${vscForeground}; + } + + background-color: ${vscBackground}; + font-family: "Lexend", sans-serif; + font-size: 13px; + padding: 8px; + color: ${vscForeground}; +`; + +export default StyledMarkdownPreview; diff --git a/extension/react-app/src/components/TextDialog.tsx b/extension/react-app/src/components/TextDialog.tsx index cba3852d..7c6ba052 100644 --- a/extension/react-app/src/components/TextDialog.tsx +++ b/extension/react-app/src/components/TextDialog.tsx @@ -5,7 +5,7 @@ import { Button, secondaryDark, vscBackground, vscForeground } from "."; import { isMetaEquivalentKeyPressed } from "../util"; const ScreenCover = styled.div` - position: absolute; + position: fixed; width: 100%; height: 100%; background-color: rgba(168, 168, 168, 0.5); diff --git a/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts index 6c0df8fc..ddf65272 100644 --- a/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts +++ b/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts @@ -1,3 +1,5 @@ +import { ContextItemId } from "../../../schema/FullState"; + abstract class AbstractContinueGUIClientProtocol { abstract sendMainInput(input: string): void; @@ -21,15 +23,15 @@ abstract class AbstractContinueGUIClientProtocol { abstract deleteAtIndex(index: number): void; - abstract deleteContextAtIndices(indices: number[]): void; + abstract deleteContextWithIds(ids: ContextItemId[]): void; abstract setEditingAtIndices(indices: number[]): void; - abstract setPinnedAtIndices(indices: number[]): void; - abstract toggleAddingHighlightedCode(): void; abstract showLogsAtIndex(index: number): void; + + abstract selectContextItem(id: string, query: string): void; } export default AbstractContinueGUIClientProtocol; diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts index 7d6c2a71..1048e956 100644 --- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts +++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts @@ -1,3 +1,4 @@ +import { ContextItemId } from "../../../schema/FullState"; import AbstractContinueGUIClientProtocol from "./AbstractContinueGUIClientProtocol"; import { Messenger, WebsocketMessenger } from "./messenger"; import { VscodeMessenger } from "./vscodeMessenger"; @@ -68,18 +69,16 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol { this.messenger.send("delete_at_index", { index }); } - deleteContextAtIndices(indices: number[]) { - this.messenger.send("delete_context_at_indices", { indices }); + deleteContextWithIds(ids: ContextItemId[]) { + this.messenger.send("delete_context_with_ids", { + ids: ids.map((id) => `${id.provider_title}-${id.item_id}`), + }); } setEditingAtIndices(indices: number[]) { this.messenger.send("set_editing_at_indices", { indices }); } - setPinnedAtIndices(indices: number[]) { - this.messenger.send("set_pinned_at_indices", { indices }); - } - toggleAddingHighlightedCode(): void { this.messenger.send("toggle_adding_highlighted_code", {}); } @@ -87,6 +86,10 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol { showLogsAtIndex(index: number): void { this.messenger.send("show_logs_at_index", { index }); } + + selectContextItem(id: string, query: string): void { + this.messenger.send("select_context_item", { id, query }); + } } export default ContinueGUIClientProtocol; diff --git a/extension/react-app/src/pages/gui.tsx b/extension/react-app/src/pages/gui.tsx index fccc9b4b..a1ba1c33 100644 --- a/extension/react-app/src/pages/gui.tsx +++ b/extension/react-app/src/pages/gui.tsx @@ -6,7 +6,7 @@ import { } from "../components"; import Loader from "../components/Loader"; import ContinueButton from "../components/ContinueButton"; -import { FullState, HighlightedRangeContext } from "../../../schema/FullState"; +import { ContextItem, FullState } from "../../../schema/FullState"; import { useCallback, useEffect, useRef, useState, useContext } from "react"; import { History } from "../../../schema/History"; import { HistoryNode } from "../../../schema/HistoryNode"; @@ -22,12 +22,16 @@ import TextDialog from "../components/TextDialog"; import HeaderButtonWithText from "../components/HeaderButtonWithText"; import ReactSwitch from "react-switch"; import { usePostHog } from "posthog-js/react"; -import { useSelector } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { RootStore } from "../redux/store"; import { postVscMessage } from "../vscode"; import UserInputContainer from "../components/UserInputContainer"; import Onboarding from "../components/Onboarding"; import { isMetaEquivalentKeyPressed } from "../util"; +import { + setBottomMessage, + setBottomMessageCloseTimeout, +} from "../redux/slices/uiStateSlice"; const TopGUIDiv = styled.div` overflow: hidden; @@ -78,15 +82,13 @@ function GUI(props: GUIProps) { const [usingFastModel, setUsingFastModel] = useState(false); const [waitingForSteps, setWaitingForSteps] = useState(false); const [userInputQueue, setUserInputQueue] = useState([]); - const [highlightedRanges, setHighlightedRanges] = useState< - HighlightedRangeContext[] - >([]); const [addingHighlightedCode, setAddingHighlightedCode] = useState(false); + const [selectedContextItems, setSelectedContextItems] = useState< + ContextItem[] + >([]); const [availableSlashCommands, setAvailableSlashCommands] = useState< { name: string; description: string }[] >([]); - const [pinned, setPinned] = useState(false); - const [showDataSharingInfo, setShowDataSharingInfo] = useState(false); const [stepsOpen, setStepsOpen] = useState([ true, true, @@ -118,6 +120,11 @@ function GUI(props: GUIProps) { const [showFeedbackDialog, setShowFeedbackDialog] = useState(false); const [feedbackDialogMessage, setFeedbackDialogMessage] = useState(""); + const dispatch = useDispatch(); + const bottomMessage = useSelector( + (state: RootStore) => state.uiState.bottomMessage + ); + const topGuiDivRef = useRef(null); const [scrollTimeout, setScrollTimeout] = useState( @@ -179,7 +186,8 @@ function GUI(props: GUIProps) { setWaitingForSteps(waitingForSteps); setHistory(state.history); - setHighlightedRanges(state.highlighted_ranges); + console.log((state as any).selected_context_items); + setSelectedContextItems(state.selected_context_items); setUserInputQueue(state.user_input_queue); setAddingHighlightedCode(state.adding_highlighted_code); setAvailableSlashCommands( @@ -214,13 +222,6 @@ function GUI(props: GUIProps) { const mainTextInputRef = useRef(null); - const deleteContextItems = useCallback( - (indices: number[]) => { - client?.deleteContextAtIndices(indices); - }, - [client] - ); - const onMainTextInput = (event?: any) => { if (mainTextInputRef.current) { let input = (mainTextInputRef.current as any).inputValue; @@ -360,11 +361,7 @@ function GUI(props: GUIProps) { }} onInputValueChange={() => {}} items={availableSlashCommands} - highlightedCodeSections={highlightedRanges} - deleteContextItems={deleteContextItems} - onTogglePin={() => { - setPinned((prev: boolean) => !prev); - }} + selectedContextItems={selectedContextItems} onToggleAddContext={() => { client?.toggleAddingHighlightedCode(); }} @@ -373,29 +370,30 @@ function GUI(props: GUIProps) {
{ + dispatch(setBottomMessageCloseTimeout(undefined)); + }} + onMouseLeave={() => { + dispatch(setBottomMessage(undefined)); + }} style={{ position: "fixed", bottom: "50px", + left: "0", + right: "0", + margin: "16px", backgroundColor: vscBackground, color: vscForeground, borderRadius: defaultBorderRadius, padding: "16px", - margin: "16px", zIndex: 100, boxShadow: `0px 0px 10px 0px ${vscForeground}`, + maxHeight: "50vh", + overflow: "scroll", }} - hidden={!showDataSharingInfo} + hidden={!bottomMessage} > - By turning on this switch, you will begin collecting accepted and - rejected suggestions in .continue/suggestions.json. This data is stored - locally on your machine and not sent anywhere. -
-
- - {dataSwitchChecked - ? "👍 Data is being collected" - : "👎 No data is being collected"} - + {bottomMessage}