summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--continuedev/src/continuedev/core/autopilot.py17
-rw-r--r--continuedev/src/continuedev/core/context.py18
-rw-r--r--continuedev/src/continuedev/core/sdk.py4
-rw-r--r--continuedev/src/continuedev/libs/llm/__init__.py2
-rw-r--r--continuedev/src/continuedev/libs/llm/anthropic.py34
-rw-r--r--continuedev/src/continuedev/libs/llm/openai.py2
-rw-r--r--continuedev/src/continuedev/plugins/policies/default.py7
-rw-r--r--continuedev/src/continuedev/server/gui.py10
-rw-r--r--continuedev/src/continuedev/server/ide.py38
-rw-r--r--continuedev/src/continuedev/server/ide_protocol.py4
-rw-r--r--continuedev/src/continuedev/server/main.py45
-rw-r--r--continuedev/src/continuedev/server/session_manager.py12
-rw-r--r--extension/package-lock.json4
-rw-r--r--extension/package.json2
-rw-r--r--extension/react-app/src/components/PillButton.tsx4
-rw-r--r--extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts2
-rw-r--r--extension/react-app/src/hooks/ContinueGUIClientProtocol.ts4
-rw-r--r--extension/src/continueIdeClient.ts16
18 files changed, 117 insertions, 108 deletions
diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index d92c51cd..a3dd854e 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -1,7 +1,7 @@
from functools import cached_property
import traceback
import time
-from typing import Any, Callable, Coroutine, Dict, List, Union
+from typing import Callable, Coroutine, Dict, List, Union
from aiohttp import ClientPayloadError
from pydantic import root_validator
@@ -54,7 +54,7 @@ class Autopilot(ContinueBaseModel):
history: History = History.from_empty()
context: Context = Context()
full_state: Union[FullState, None] = None
- context_manager: Union[ContextManager, None] = None
+ context_manager: ContextManager = ContextManager()
continue_sdk: ContinueSDK = None
_on_update_callbacks: List[Callable[[FullState], None]] = []
@@ -66,19 +66,22 @@ class Autopilot(ContinueBaseModel):
_user_input_queue = AsyncSubscriptionQueue()
_retry_queue = AsyncSubscriptionQueue()
+ started: bool = False
+
async def start(self):
self.continue_sdk = await ContinueSDK.create(self)
if override_policy := self.continue_sdk.config.policy_override:
self.policy = override_policy
# Load documents into the search index
- self.context_manager = await ContextManager.create(
+ await self.context_manager.start(
self.continue_sdk.config.context_providers + [
HighlightedCodeContextProvider(ide=self.ide),
FileContextProvider(workspace_dir=self.ide.workspace_directory)
])
await self.context_manager.load_index(self.ide.workspace_directory)
+ self.started = True
class Config:
arbitrary_types_allowed = True
@@ -98,7 +101,7 @@ class Autopilot(ContinueBaseModel):
user_input_queue=self._main_user_input_queue,
slash_commands=self.get_available_slash_commands(),
adding_highlighted_code=self.context_manager.context_providers[
- "code"].adding_highlighted_code if self.context_manager is not None else False,
+ "code"].adding_highlighted_code if "code" in self.context_manager.context_providers else False,
selected_context_items=await self.context_manager.get_selected_items() if self.context_manager is not None else [],
)
self.full_state = full_state
@@ -201,7 +204,7 @@ class Autopilot(ContinueBaseModel):
await self.update_subscribers()
async def set_editing_at_ids(self, ids: List[str]):
- self.context_manager.context_providers["code"].set_editing_at_ids(ids)
+ await 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]:
@@ -244,7 +247,7 @@ class Autopilot(ContinueBaseModel):
try:
observation = await step(self.continue_sdk)
except Exception as e:
- if self.history.timeline[index_of_history_node].deleted:
+ if index_of_history_node >= len(self.history.timeline) or self.history.timeline[index_of_history_node].deleted:
# If step was deleted/cancelled, don't show error or allow retry
return None
@@ -301,7 +304,7 @@ class Autopilot(ContinueBaseModel):
self._step_depth -= 1
# Add observation to history, unless already attached error observation
- if not caught_error:
+ if not caught_error and index_of_history_node < len(self.history.timeline):
self.history.timeline[index_of_history_node].observation = observation
self.history.timeline[index_of_history_node].active = False
await self.update_subscribers()
diff --git a/continuedev/src/continuedev/core/context.py b/continuedev/src/continuedev/core/context.py
index e968c35c..20725216 100644
--- a/continuedev/src/continuedev/core/context.py
+++ b/continuedev/src/continuedev/core/context.py
@@ -133,14 +133,19 @@ class ContextManager:
"""
return sum([await provider.get_chat_messages() for provider in self.context_providers.values()], [])
- def __init__(self, context_providers: List[ContextProvider]):
+ def __init__(self):
+ self.context_providers = {}
+ self.provider_titles = set()
+
+ async def start(self, context_providers: List[ContextProvider]):
+ """
+ Starts the context manager.
+ """
self.context_providers = {
prov.title: prov for prov in context_providers}
self.provider_titles = {
provider.title for provider in context_providers}
- @classmethod
- async def create(cls, context_providers: List[ContextProvider]):
async with Client('http://localhost:7700') as search_client:
meilisearch_running = True
try:
@@ -154,10 +159,9 @@ class ContextManager:
if not meilisearch_running:
logger.warning(
"MeiliSearch not running, avoiding any dependent context providers")
- context_providers = list(
- filter(lambda cp: cp.title == "code", context_providers))
-
- return cls(context_providers)
+ self.context_providers = {
+ title: provider for title, provider in self.context_providers.items() if title == "code"
+ }
async def load_index(self, workspace_dir: str):
for _, provider in self.context_providers.items():
diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py
index a5b16168..30fcc144 100644
--- a/continuedev/src/continuedev/core/sdk.py
+++ b/continuedev/src/continuedev/core/sdk.py
@@ -195,10 +195,8 @@ class ContinueSDK(AbstractContinueSDK):
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)
+ history_context.insert(-1, msg)
return history_context
diff --git a/continuedev/src/continuedev/libs/llm/__init__.py b/continuedev/src/continuedev/libs/llm/__init__.py
index 50577993..40edb99b 100644
--- a/continuedev/src/continuedev/libs/llm/__init__.py
+++ b/continuedev/src/continuedev/libs/llm/__init__.py
@@ -10,7 +10,7 @@ class LLM(ContinueBaseModel, ABC):
requires_unique_id: bool = False
requires_write_log: bool = False
- system_message: Union[str, None] = None
+ system_message: Optional[str] = None
@abstractproperty
def name(self):
diff --git a/continuedev/src/continuedev/libs/llm/anthropic.py b/continuedev/src/continuedev/libs/llm/anthropic.py
index ec1b7e40..8a548223 100644
--- a/continuedev/src/continuedev/libs/llm/anthropic.py
+++ b/continuedev/src/continuedev/libs/llm/anthropic.py
@@ -1,33 +1,33 @@
from functools import cached_property
import time
-from typing import Any, Coroutine, Dict, Generator, List, Optional, Union
+from typing import Any, Callable, Coroutine, Dict, Generator, List, Optional, Union
from ...core.main import ChatMessage
from anthropic import HUMAN_PROMPT, AI_PROMPT, AsyncAnthropic
from ..llm import LLM
-from ..util.count_tokens import compile_chat_messages, DEFAULT_ARGS, count_tokens
+from ..util.count_tokens import compile_chat_messages, DEFAULT_ARGS, count_tokens, format_chat_messages
class AnthropicLLM(LLM):
model: str = "claude-2"
requires_api_key: str = "ANTHROPIC_API_KEY"
+ requires_write_log = True
_async_client: AsyncAnthropic = None
class Config:
arbitrary_types_allowed = True
- def __init__(self, model: str, system_message: str = None):
- self.model = model
- self.system_message = system_message
+ write_log: Optional[Callable[[str], None]] = None
- async def start(self, *, api_key: Optional[str] = None, **kwargs):
+ async def start(self, *, api_key: Optional[str] = None, write_log: Callable[[str], None], **kwargs):
+ self.write_log = write_log
self._async_client = AsyncAnthropic(api_key=api_key)
async def stop(self):
pass
- @cached_property
+ @property
def name(self):
return self.model
@@ -72,12 +72,18 @@ class AnthropicLLM(LLM):
args.update(kwargs)
args["stream"] = True
args = self._transform_args(args)
+ prompt = f"{HUMAN_PROMPT} {prompt} {AI_PROMPT}"
+ self.write_log(f"Prompt: \n\n{prompt}")
+ completion = ""
async for chunk in await self._async_client.completions.create(
- prompt=f"{HUMAN_PROMPT} {prompt} {AI_PROMPT}",
+ prompt=prompt,
**args
):
yield chunk.completion
+ completion += chunk.completion
+
+ self.write_log(f"Completion: \n\n{completion}")
async def stream_chat(self, messages: List[ChatMessage] = None, **kwargs) -> Generator[Union[Any, List, Dict], None, None]:
args = self.default_args.copy()
@@ -86,7 +92,10 @@ class AnthropicLLM(LLM):
args = self._transform_args(args)
messages = compile_chat_messages(
- args["model"], messages, self.context_length, self.context_length, args["max_tokens_to_sample"], functions=args.get("functions", None), system_message=self.system_message)
+ args["model"], messages, self.context_length, args["max_tokens_to_sample"], functions=args.get("functions", None), system_message=self.system_message)
+
+ completion = ""
+ self.write_log(f"Prompt: \n\n{format_chat_messages(messages)}")
async for chunk in await self._async_client.completions.create(
prompt=self.__messages_to_prompt(messages),
**args
@@ -95,6 +104,9 @@ class AnthropicLLM(LLM):
"role": "assistant",
"content": chunk.completion
}
+ completion += chunk.completion
+
+ self.write_log(f"Completion: \n\n{completion}")
async def complete(self, prompt: str, with_history: List[ChatMessage] = None, **kwargs) -> Coroutine[Any, Any, str]:
args = {**self.default_args, **kwargs}
@@ -102,9 +114,13 @@ class AnthropicLLM(LLM):
messages = compile_chat_messages(
args["model"], with_history, self.context_length, args["max_tokens_to_sample"], prompt, functions=None, system_message=self.system_message)
+
+ completion = ""
+ self.write_log(f"Prompt: \n\n{format_chat_messages(messages)}")
resp = (await self._async_client.completions.create(
prompt=self.__messages_to_prompt(messages),
**args
)).completion
+ self.write_log(f"Completion: \n\n{resp}")
return resp
diff --git a/continuedev/src/continuedev/libs/llm/openai.py b/continuedev/src/continuedev/libs/llm/openai.py
index fce6e8ab..99c851ca 100644
--- a/continuedev/src/continuedev/libs/llm/openai.py
+++ b/continuedev/src/continuedev/libs/llm/openai.py
@@ -1,5 +1,3 @@
-from functools import cached_property
-import json
from typing import Any, Callable, Coroutine, Dict, Generator, List, Literal, Union, Optional
from pydantic import BaseModel
diff --git a/continuedev/src/continuedev/plugins/policies/default.py b/continuedev/src/continuedev/plugins/policies/default.py
index 523c2cf4..0d74fa3f 100644
--- a/continuedev/src/continuedev/plugins/policies/default.py
+++ b/continuedev/src/continuedev/plugins/policies/default.py
@@ -1,5 +1,5 @@
from textwrap import dedent
-from typing import Union
+from typing import Type, Union
from ..steps.chat import SimpleChatStep
from ..steps.welcome import WelcomeStep
@@ -46,7 +46,8 @@ def parse_custom_command(inp: str, config: ContinueConfig) -> Union[None, Step]:
class DefaultPolicy(Policy):
- default_step: Step = SimpleChatStep()
+ default_step: Type[Step] = SimpleChatStep
+ default_params: dict = {}
def next(self, config: ContinueConfig, history: History) -> Step:
# At the very start, run initial Steps spcecified in the config
@@ -75,6 +76,6 @@ class DefaultPolicy(Policy):
if user_input.startswith("/edit"):
return EditHighlightedCodeStep(user_input=user_input[5:])
- return self.default_step.copy()
+ return self.default_step(**self.default_params)
return None
diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py
index cf18c56b..7c89c5c2 100644
--- a/continuedev/src/continuedev/server/gui.py
+++ b/continuedev/src/continuedev/server/gui.py
@@ -93,8 +93,8 @@ class GUIProtocolServer(AbstractGUIProtocolServer):
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_editing_at_ids":
+ self.on_set_editing_at_ids(data["ids"])
elif message_type == "show_logs_at_index":
self.on_show_logs_at_index(data["index"])
elif message_type == "select_context_item":
@@ -138,9 +138,9 @@ class GUIProtocolServer(AbstractGUIProtocolServer):
create_async_task(
self.session.autopilot.toggle_adding_highlighted_code(), self.on_error)
- def on_set_editing_at_indices(self, indices: List[int]):
+ def on_set_editing_at_ids(self, ids: List[str]):
create_async_task(
- self.session.autopilot.set_editing_at_indices(indices), self.on_error)
+ self.session.autopilot.set_editing_at_ids(ids), self.on_error)
def on_show_logs_at_index(self, index: int):
name = f"continue_logs.txt"
@@ -190,7 +190,7 @@ async def websocket_endpoint(websocket: WebSocket, session: Session = Depends(we
posthog_logger.capture_event("gui_error", {
"error_title": e.__str__() or e.__repr__(), "error_message": err_msg})
- await protocol.session.autopilot.continue_sdk.run_step(DisplayErrorStep(e=e))
+ await session.autopilot.ide.showMessage(err_msg)
raise e
finally:
diff --git a/continuedev/src/continuedev/server/ide.py b/continuedev/src/continuedev/server/ide.py
index 6124f3bd..9797a8b7 100644
--- a/continuedev/src/continuedev/server/ide.py
+++ b/continuedev/src/continuedev/server/ide.py
@@ -1,7 +1,7 @@
# This is a separate server from server/main.py
import json
import os
-from typing import Any, List, Type, TypeVar, Union
+from typing import Any, Coroutine, List, Type, TypeVar, Union
import uuid
from fastapi import WebSocket, APIRouter
from starlette.websockets import WebSocketState, WebSocketDisconnect
@@ -211,8 +211,6 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
else:
raise ValueError("Unknown message type", message_type)
- # ------------------------------- #
- # Request actions in IDE, doesn't matter which Session
async def showSuggestion(self, file_edit: FileEdit):
await self._send_json("showSuggestion", {
"edit": file_edit.dict()
@@ -232,6 +230,11 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
"open": open
})
+ async def showMessage(self, message: str):
+ await self._send_json("showMessage", {
+ "message": message
+ })
+
async def showVirtualFile(self, name: str, contents: str):
await self._send_json("showVirtualFile", {
"name": name,
@@ -275,13 +278,12 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
# Just need connect the suggestionId to the IDE (and the gui)
return any([r.accepted for r in responses])
- # ------------------------------- #
- # Here needs to pass message onto the Autopilot OR Autopilot just subscribes.
- # This is where you might have triggers: plugins can subscribe to certian events
- # like file changes, tracebacks, etc...
-
- def on_error(self, e: Exception):
- return self.session_manager.sessions[self.session_id].autopilot.continue_sdk.run_step(DisplayErrorStep(e=e))
+ def on_error(self, e: Exception) -> Coroutine:
+ try:
+ return self.session_manager.sessions[self.session_id].autopilot.continue_sdk.run_step(DisplayErrorStep(e=e))
+ except:
+ err_msg = '\n'.join(traceback.format_exception(e))
+ return self.showMessage(f"Error in Continue server: {err_msg}")
def onAcceptRejectSuggestion(self, accepted: bool):
posthog_logger.capture_event("accept_reject_suggestion", {
@@ -307,7 +309,9 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
def __get_autopilot(self):
if self.session_id not in self.session_manager.sessions:
return None
- return self.session_manager.sessions[self.session_id].autopilot
+
+ autopilot = self.session_manager.sessions[self.session_id].autopilot
+ return autopilot if autopilot.started else None
def onFileEdits(self, edits: List[FileEditWithFullContents]):
if autopilot := self.__get_autopilot():
@@ -442,6 +446,7 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
@router.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket, session_id: str = None):
try:
+ # Accept the websocket connection
await websocket.accept()
logger.debug(f"Accepted websocket connection from {websocket.client}")
await websocket.send_json({"messageType": "connected", "data": {}})
@@ -453,6 +458,7 @@ async def websocket_endpoint(websocket: WebSocket, session_id: str = None):
logger.debug("Failed to start MeiliSearch")
logger.debug(e)
+ # Message handler
def handle_msg(msg):
message = json.loads(msg)
@@ -465,6 +471,7 @@ async def websocket_endpoint(websocket: WebSocket, session_id: str = None):
create_async_task(
ideProtocolServer.handle_json(message_type, data), ideProtocolServer.on_error)
+ # Initialize the IDE Protocol Server
ideProtocolServer = IdeProtocolServer(session_manager, websocket)
if session_id is not None:
session_manager.registered_ides[session_id] = ideProtocolServer
@@ -475,20 +482,23 @@ async def websocket_endpoint(websocket: WebSocket, session_id: str = None):
for other_msg in other_msgs:
handle_msg(other_msg)
+ # Handle messages
while AppStatus.should_exit is False:
message = await websocket.receive_text()
handle_msg(message)
- logger.debug("Closing ide websocket")
except WebSocketDisconnect as e:
- logger.debug("IDE wbsocket disconnected")
+ logger.debug("IDE websocket disconnected")
except Exception as e:
logger.debug(f"Error in ide websocket: {e}")
err_msg = '\n'.join(traceback.format_exception(e))
posthog_logger.capture_event("gui_error", {
"error_title": e.__str__() or e.__repr__(), "error_message": err_msg})
- await session_manager.sessions[session_id].autopilot.continue_sdk.run_step(DisplayErrorStep(e=e))
+ if session_id is not None and session_id in session_manager.sessions:
+ await session_manager.sessions[session_id].autopilot.continue_sdk.run_step(DisplayErrorStep(e=e))
+ elif ideProtocolServer is not None:
+ await ideProtocolServer.showMessage(f"Error in Continue server: {err_msg}")
raise e
finally:
diff --git a/continuedev/src/continuedev/server/ide_protocol.py b/continuedev/src/continuedev/server/ide_protocol.py
index 0ae7e7fa..72b410d4 100644
--- a/continuedev/src/continuedev/server/ide_protocol.py
+++ b/continuedev/src/continuedev/server/ide_protocol.py
@@ -24,6 +24,10 @@ class AbstractIdeProtocolServer(ABC):
"""Set whether a file is open"""
@abstractmethod
+ async def showMessage(self, message: str):
+ """Show a message to the user"""
+
+ @abstractmethod
async def showVirtualFile(self, name: str, contents: str):
"""Show a virtual file"""
diff --git a/continuedev/src/continuedev/server/main.py b/continuedev/src/continuedev/server/main.py
index 468bc855..f8dfb009 100644
--- a/continuedev/src/continuedev/server/main.py
+++ b/continuedev/src/continuedev/server/main.py
@@ -1,5 +1,4 @@
import asyncio
-import sys
import time
import psutil
import os
@@ -8,13 +7,11 @@ from fastapi.middleware.cors import CORSMiddleware
import atexit
import uvicorn
import argparse
-import logging.config
from .ide import router as ide_router
from .gui import router as gui_router
from .session_manager import session_manager
-from ..libs.util.paths import getLogFilePath
from ..libs.util.logging import logger
app = FastAPI()
@@ -38,25 +35,6 @@ def health():
return {"status": "ok"}
-class Logger(object):
- def __init__(self, log_file: str):
- self.terminal = sys.stdout
- self.log = open(log_file, "a")
-
- def write(self, message):
- self.terminal.write(message)
- self.log.write(message)
-
- def flush(self):
- # this flush method is needed for python 3 compatibility.
- # this handles the flush command by doing nothing.
- # you might want to specify some extra behavior here.
- pass
-
- def isatty(self):
- return False
-
-
try:
# add cli arg for server port
parser = argparse.ArgumentParser()
@@ -71,7 +49,6 @@ except Exception as e:
def run_server():
config = uvicorn.Config(app, host="127.0.0.1", port=args.port)
server = uvicorn.Server(config)
-
server.run()
@@ -87,32 +64,10 @@ def cleanup():
loop.close()
-def cpu_usage_report():
- process = psutil.Process(os.getpid())
- # Call cpu_percent once to start measurement, but ignore the result
- process.cpu_percent(interval=None)
- # Wait for a short period of time
- time.sleep(1)
- # Call cpu_percent again to get the CPU usage over the interval
- cpu_usage = process.cpu_percent(interval=None)
- logger.debug(f"CPU usage: {cpu_usage}%")
-
-
atexit.register(cleanup)
if __name__ == "__main__":
try:
- # Uncomment to get CPU usage reports
- # import threading
-
- # def cpu_usage_loop():
- # while True:
- # cpu_usage_report()
- # time.sleep(2)
-
- # cpu_thread = threading.Thread(target=cpu_usage_loop)
- # cpu_thread.start()
-
run_server()
except Exception as e:
logger.debug(f"Error starting Continue server: {e}")
diff --git a/continuedev/src/continuedev/server/session_manager.py b/continuedev/src/continuedev/server/session_manager.py
index b5580fe8..56c92307 100644
--- a/continuedev/src/continuedev/server/session_manager.py
+++ b/continuedev/src/continuedev/server/session_manager.py
@@ -1,15 +1,14 @@
import os
import traceback
from fastapi import WebSocket
-from typing import Any, Dict, List, Union
+from typing import Any, Coroutine, Dict, Union
from uuid import uuid4
import json
from fastapi.websockets import WebSocketState
-from ..plugins.steps.core.core import DisplayErrorStep, MessageStep
+from ..plugins.steps.core.core import MessageStep
from ..libs.util.paths import getSessionFilePath, getSessionsFolderPath
-from ..models.filesystem_edit import FileEditWithFullContents
from ..core.main import FullState, HistoryNode
from ..core.autopilot import Autopilot
from .ide_protocol import AbstractIdeProtocolServer
@@ -90,8 +89,11 @@ class SessionManager:
))
logger.warning(f"Error loading context manager: {e}")
- create_async_task(autopilot.run_policy(), lambda e: autopilot.continue_sdk.run_step(
- DisplayErrorStep(e=e)))
+ def on_error(e: Exception) -> Coroutine:
+ err_msg = '\n'.join(traceback.format_exception(e))
+ return ide.showMessage(f"Error in Continue server: {err_msg}")
+
+ create_async_task(autopilot.run_policy(), on_error)
return session
async def remove_session(self, session_id: str):
diff --git a/extension/package-lock.json b/extension/package-lock.json
index d6c53eb2..60702457 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "continue",
- "version": "0.0.233",
+ "version": "0.0.241",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "continue",
- "version": "0.0.233",
+ "version": "0.0.241",
"license": "Apache-2.0",
"dependencies": {
"@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index d7334b2b..744fe773 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.233",
+ "version": "0.0.241",
"publisher": "Continue",
"engines": {
"vscode": "^1.67.0"
diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx
index e3d05711..0b1aa23d 100644
--- a/extension/react-app/src/components/PillButton.tsx
+++ b/extension/react-app/src/components/PillButton.tsx
@@ -168,7 +168,9 @@ const PillButton = (props: PillButtonProps) => {
data-tooltip-id={`edit-${props.index}`}
backgroundColor={"#8800aa55"}
onClick={() => {
- client?.setEditingAtIndices([props.index]);
+ client?.setEditingAtIds([
+ props.item.description.id.item_id,
+ ]);
}}
>
<PaintBrush
diff --git a/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts
index 8e3735ec..8d8b7b7e 100644
--- a/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts
+++ b/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts
@@ -23,7 +23,7 @@ abstract class AbstractContinueGUIClientProtocol {
abstract deleteContextWithIds(ids: ContextItemId[]): void;
- abstract setEditingAtIndices(indices: number[]): void;
+ abstract setEditingAtIds(ids: string[]): void;
abstract toggleAddingHighlightedCode(): void;
diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
index 5a5d4c30..b6dd43d9 100644
--- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
+++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
@@ -78,8 +78,8 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol {
});
}
- setEditingAtIndices(indices: number[]) {
- this.messenger.send("set_editing_at_indices", { indices });
+ setEditingAtIds(ids: string[]) {
+ this.messenger.send("set_editing_at_ids", { ids });
}
toggleAddingHighlightedCode(): void {
diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts
index b0fb9e8d..220edafa 100644
--- a/extension/src/continueIdeClient.ts
+++ b/extension/src/continueIdeClient.ts
@@ -192,6 +192,8 @@ class IdeProtocolClient {
});
}
+ visibleMessages: Set<string> = new Set();
+
async handleMessage(
messageType: string,
data: any,
@@ -254,6 +256,20 @@ class IdeProtocolClient {
this.openFile(data.filepath);
// TODO: Close file if False
break;
+ case "showMessage":
+ if (!this.visibleMessages.has(data.message)) {
+ this.visibleMessages.add(data.message);
+ vscode.window
+ .showInformationMessage(data.message, "Copy Traceback", "View Logs")
+ .then((selection) => {
+ if (selection === "View Logs") {
+ vscode.commands.executeCommand("continue.viewLogs");
+ } else if (selection === "Copy Traceback") {
+ vscode.env.clipboard.writeText(data.message);
+ }
+ });
+ }
+ break;
case "showVirtualFile":
this.showVirtualFile(data.name, data.contents);
break;