diff options
-rw-r--r-- | continuedev/src/continuedev/core/autopilot.py | 4 | ||||
-rw-r--r-- | continuedev/src/continuedev/libs/util/telemetry.py | 4 | ||||
-rw-r--r-- | continuedev/src/continuedev/server/ide.py | 30 | ||||
-rw-r--r-- | continuedev/src/continuedev/server/ide_protocol.py | 4 | ||||
-rw-r--r-- | continuedev/src/continuedev/steps/feedback.py | 5 | ||||
-rw-r--r-- | extension/package-lock.json | 4 | ||||
-rw-r--r-- | extension/package.json | 2 | ||||
-rw-r--r-- | extension/react-app/src/tabs/gui.tsx | 194 | ||||
-rw-r--r-- | extension/scripts/continuedev-0.1.1-py3-none-any.whl | bin | 0 -> 81413 bytes | |||
-rw-r--r-- | extension/src/continueIdeClient.ts | 9 |
10 files changed, 153 insertions, 103 deletions
diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py index 0874bbc5..703a73af 100644 --- a/continuedev/src/continuedev/core/autopilot.py +++ b/continuedev/src/continuedev/core/autopilot.py @@ -102,8 +102,8 @@ class Autopilot(ContinueBaseModel): await self.update_subscribers() async def _run_singular_step(self, step: "Step", is_future_step: bool = False) -> Coroutine[Observation, None, None]: - capture_event( - 'step run', {'step_name': step.name, 'params': step.dict()}) + capture_event(self.continue_sdk.ide.unique_id, 'step run', { + 'step_name': step.name, 'params': step.dict()}) if not is_future_step: # Check manual edits buffer, clear out if needed by creating a ManualEditStep diff --git a/continuedev/src/continuedev/libs/util/telemetry.py b/continuedev/src/continuedev/libs/util/telemetry.py index d6345c25..03ec93c6 100644 --- a/continuedev/src/continuedev/libs/util/telemetry.py +++ b/continuedev/src/continuedev/libs/util/telemetry.py @@ -6,7 +6,7 @@ posthog = Posthog('phc_JS6XFROuNbhJtVCEdTSYk6gl5ArRrTNMpCcguAXlSPs', host='https://app.posthog.com') -def capture_event(event_name, event_properties): +def capture_event(unique_id: str, event_name, event_properties): config = load_config('.continue/config.json') if config.allow_anonymous_telemetry: - posthog.capture("not distinct :(", event_name, event_properties) + posthog.capture(unique_id, event_name, event_properties) diff --git a/continuedev/src/continuedev/server/ide.py b/continuedev/src/continuedev/server/ide.py index f4ea1071..c53149d8 100644 --- a/continuedev/src/continuedev/server/ide.py +++ b/continuedev/src/continuedev/server/ide.py @@ -81,9 +81,29 @@ class RunCommandResponse(BaseModel): output: str +class UniqueIdResponse(BaseModel): + uniqueId: str + + T = TypeVar("T", bound=BaseModel) +class cached_property_no_none: + def __init__(self, func): + self.func = func + + def __get__(self, instance, owner): + if instance is None: + return self + value = self.func(instance) + if value is not None: + setattr(instance, self.func.__name__, value) + return value + + def __repr__(self): + return f"<cached_property_no_none '{self.func.__name__}'>" + + class IdeProtocolServer(AbstractIdeProtocolServer): websocket: WebSocket session_manager: SessionManager @@ -115,7 +135,7 @@ class IdeProtocolServer(AbstractIdeProtocolServer): fileEdits = list( map(lambda d: FileEditWithFullContents.parse_obj(d), data["fileEdits"])) self.onFileEdits(fileEdits) - elif message_type in ["highlightedCode", "openFiles", "readFile", "editFile", "workspaceDirectory", "getUserSecret", "runCommand"]: + elif message_type in ["highlightedCode", "openFiles", "readFile", "editFile", "workspaceDirectory", "getUserSecret", "runCommand", "uniqueId"]: self.sub_queue.post(message_type, data) else: raise ValueError("Unknown message type", message_type) @@ -200,10 +220,18 @@ class IdeProtocolServer(AbstractIdeProtocolServer): resp = await self._send_and_receive_json({}, WorkspaceDirectoryResponse, "workspaceDirectory") return resp.workspaceDirectory + async def get_unique_id(self) -> str: + resp = await self._send_and_receive_json({}, UniqueIdResponse, "uniqueId") + return resp.uniqueId + @cached_property def workspace_directory(self) -> str: return asyncio.run(self.getWorkspaceDirectory()) + @cached_property_no_none + def unique_id(self) -> str: + return asyncio.run(self.get_unique_id()) + async def getHighlightedCode(self) -> List[RangeInFile]: resp = await self._send_and_receive_json({}, HighlightedCodeResponse, "highlightedCode") return resp.highlightedCode diff --git a/continuedev/src/continuedev/server/ide_protocol.py b/continuedev/src/continuedev/server/ide_protocol.py index a937ad75..1d98f4a1 100644 --- a/continuedev/src/continuedev/server/ide_protocol.py +++ b/continuedev/src/continuedev/server/ide_protocol.py @@ -94,3 +94,7 @@ class AbstractIdeProtocolServer(ABC): @abstractproperty def workspace_directory(self) -> str: """Get the workspace directory""" + + @abstractproperty + def unique_id(self) -> str: + """Get a unique ID for this IDE""" diff --git a/continuedev/src/continuedev/steps/feedback.py b/continuedev/src/continuedev/steps/feedback.py index 96081756..6f6a9b15 100644 --- a/continuedev/src/continuedev/steps/feedback.py +++ b/continuedev/src/continuedev/steps/feedback.py @@ -10,7 +10,8 @@ class FeedbackStep(Step): name = "Thanks for your feedback!" async def describe(self, models: Models): - return f"`{self.user_input}`\n\nWe'll see your feedback and make improvements as soon as possible. If you'd like to directly email us, you can send an email to [nate@continue.dev](mailto:nate@continue.dev?subject=Feedback%20On%20Continue)." + return f"`{self.user_input}`\n\nWe'll see your feedback and make improvements as soon as possible. If you'd like to directly email us, you can contact [nate@continue.dev](mailto:nate@continue.dev?subject=Feedback%20On%20Continue)." async def run(self, sdk: ContinueSDK): - capture_event("feedback", {"feedback": self.user_input}) + capture_event(sdk.ide.unique_id, "feedback", + {"feedback": self.user_input}) diff --git a/extension/package-lock.json b/extension/package-lock.json index 6edc38f9..afa8ab2d 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.36", + "version": "0.0.38", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.36", + "version": "0.0.38", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index 91d687ab..4b86f4ea 100644 --- a/extension/package.json +++ b/extension/package.json @@ -14,7 +14,7 @@ "displayName": "Continue", "pricing": "Free", "description": "Refine code 10x faster", - "version": "0.0.36", + "version": "0.0.38", "publisher": "Continue", "engines": { "vscode": "^1.74.0" diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index 55c2b763..70bab352 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -21,6 +21,11 @@ import { import ComboBox from "../components/ComboBox"; import TextDialog from "../components/TextDialog"; +const MainDiv = styled.div` + display: grid; + grid-template-rows: 1fr auto; +`; + let TopGUIDiv = styled.div` display: grid; grid-template-columns: 1fr; @@ -39,10 +44,11 @@ const TopBar = styled.div` display: flex; flex-direction: row; gap: 8px; - justify-content: center; + justify-content: right; padding: 8px; align-items: center; - border-bottom: 0.1px solid gray; + margin-top: 8px; + border-top: 0.1px solid gray; `; interface GUIProps { @@ -294,101 +300,103 @@ function GUI(props: GUIProps) { setShowFeedbackDialog(false); }} ></TextDialog> - <TopGUIDiv - ref={topGuiDivRef} - onKeyDown={(e) => { - if (e.key === "Enter" && e.ctrlKey) { - onMainTextInput(); - } - }} - > - <TopBar> - <a href="https://continue.dev/docs" className="no-underline"> - <HeaderButton style={{ padding: "3px" }}> - Continue Docs - <BookOpen size="1.6em" /> - </HeaderButton> - </a> - <HeaderButton - style={{ padding: "3px" }} - onClick={() => { - // Set dialog open - setShowFeedbackDialog(true); - }} - > - Feedback - <ChatBubbleOvalLeftEllipsis size="1.6em" /> - </HeaderButton> - <HeaderButton - onClick={() => { - client?.sendClear(); + <MainDiv> + <TopGUIDiv + ref={topGuiDivRef} + onKeyDown={(e) => { + if (e.key === "Enter" && e.ctrlKey) { + onMainTextInput(); + } + }} + > + {typeof client === "undefined" && ( + <> + <Loader></Loader> + <p style={{ textAlign: "center" }}> + Trying to reconnect with server... + </p> + </> + )} + {history?.timeline.map((node: HistoryNode, index: number) => { + return ( + <StepContainer + key={index} + onUserInput={(input: string) => { + onStepUserInput(input, index); + }} + inFuture={index > history?.current_index} + historyNode={node} + onRefinement={(input: string) => { + client?.sendRefinementInput(input, index); + }} + onReverse={() => { + client?.reverseToIndex(index); + }} + onRetry={() => { + client?.retryAtIndex(index); + setWaitingForSteps(true); + }} + onDelete={() => { + client?.deleteAtIndex(index); + }} + /> + ); + })} + {waitingForSteps && <Loader></Loader>} + + <div> + {userInputQueue.map((input) => { + return <UserInputQueueItem>{input}</UserInputQueueItem>; + })} + </div> + + <ComboBox + disabled={ + history?.timeline.length + ? history.timeline[history.current_index].step.name === + "Waiting for user confirmation" + : false + } + ref={mainTextInputRef} + onEnter={(e) => { + onMainTextInput(); + e.stopPropagation(); + e.preventDefault(); }} - style={{ padding: "3px" }} - > - Clear History - <Trash size="1.6em" /> - </HeaderButton> - </TopBar> + onInputValueChange={() => {}} + items={availableSlashCommands} + /> + <ContinueButton onClick={onMainTextInput} /> - {typeof client === "undefined" && ( - <> - <Loader></Loader> - <p style={{ textAlign: "center" }}> - Trying to reconnect with server... - </p> - </> - )} - {history?.timeline.map((node: HistoryNode, index: number) => { - return ( - <StepContainer - key={index} - onUserInput={(input: string) => { - onStepUserInput(input, index); + <TopBar> + <a href="https://continue.dev/docs" className="no-underline"> + <HeaderButton style={{ padding: "3px" }}> + Continue Docs + <BookOpen size="1.6em" /> + </HeaderButton> + </a> + <HeaderButton + style={{ padding: "3px" }} + onClick={() => { + // Set dialog open + setShowFeedbackDialog(true); }} - inFuture={index > history?.current_index} - historyNode={node} - onRefinement={(input: string) => { - client?.sendRefinementInput(input, index); - }} - onReverse={() => { - client?.reverseToIndex(index); - }} - onRetry={() => { - client?.retryAtIndex(index); - setWaitingForSteps(true); - }} - onDelete={() => { - client?.deleteAtIndex(index); + > + Feedback + <ChatBubbleOvalLeftEllipsis size="1.6em" /> + </HeaderButton> + <HeaderButton + onClick={() => { + client?.sendClear(); }} - /> - ); - })} - {waitingForSteps && <Loader></Loader>} - - <div> - {userInputQueue.map((input) => { - return <UserInputQueueItem>{input}</UserInputQueueItem>; - })} - </div> - - <ComboBox - disabled={ - history?.timeline.length - ? history.timeline[history.current_index].step.name === - "Waiting for user confirmation" - : false - } - ref={mainTextInputRef} - onEnter={(e) => { - onMainTextInput(); - e.stopPropagation(); - e.preventDefault(); - }} - onInputValueChange={() => {}} - items={availableSlashCommands} - /> - <ContinueButton onClick={onMainTextInput} /> - </TopGUIDiv> + style={{ padding: "3px" }} + > + Clear History + <Trash size="1.6em" /> + </HeaderButton> + </TopBar> + </TopGUIDiv> + </MainDiv> </> ); } diff --git a/extension/scripts/continuedev-0.1.1-py3-none-any.whl b/extension/scripts/continuedev-0.1.1-py3-none-any.whl Binary files differnew file mode 100644 index 00000000..b3e8229a --- /dev/null +++ b/extension/scripts/continuedev-0.1.1-py3-none-any.whl diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts index 3308068a..16941c70 100644 --- a/extension/src/continueIdeClient.ts +++ b/extension/src/continueIdeClient.ts @@ -77,6 +77,11 @@ class IdeProtocolClient { workspaceDirectory: this.getWorkspaceDirectory(), }); break; + case "uniqueId": + this.messenger?.send("uniqueId", { + uniqueId: this.getUniqueId(), + }); + break; case "getUserSecret": this.messenger?.send("getUserSecret", { value: await this.getUserSecret(data.key), @@ -128,6 +133,10 @@ class IdeProtocolClient { return vscode.workspace.workspaceFolders[0].uri.fsPath; } + getUniqueId() { + return vscode.env.machineId; + } + // ------------------------------------ // // On message handlers |