The Continue Extension can be seen as 3 main entities:
- GUI - a React App embedded in the IDE, which provides a chat interface, etc.
- Core - code shared between extensions (and the GUI)
- IDE - code specifically required to build the IDE extension and and access IDE functionality i.e. VS Code or Jetbrains
The GUI, IDE, and Core communicate through messaging protocols, whose message names and data types are defined in Typescript in core/protocol
These protocols are defined specific to each origin/destination combination, i.e., specific message types are defined for e.g. GUI -> Core, Core -> IDE, IDE -> GUI, etc.
Note that Jetbrains (written in Kotlin) does not currently have access to these types, so must be careful with Jetbrains messaging.
Since the GUI is embedded in the IDE and can only directly communicate with the IDE, the idea of "pass through" messaging is implemented to pass certain messages directly from the GUI to the Core and vice versa
Continue utilizes a variety of messaging channels depending on platform, environment, extension capabilities, etc.
- TCP - websockets port listeners
- IPC (Inter-Process Communication) channels
- In-process communication
- Browser window message events
All of these messenger implementations utilize some combination of these paradigms for sending and receiving messages:
post
- sends a message with no expectation for a responsesend
- sends a message with an IDrequest
- sends a message with an ID and then listens (async) for a response with the same ID to resolverespond
- responds to a request with same message IDinvoke
- sends a message to itself to invoke its own listenerson
- adds a listener to a specific message type
- The GUI and IDE communicate through browser window events/methods
- Sending Messages
- Messages are sent to the IDE using an
IdeMessenger
, which providesrequest
,post
,respond
, andsend
functionality - This is implemented with an
ideMessenger
context available to the entire React app, which contains an instance ofIdeMessenger
- It also exposes
ideMessenger.ide
as syntactic sugar - an instance ofMessageIde
which provides explicit methods for each method, but simply callsideMessenger.request("message")
, - In VS Code's Electron environment, the GUI can post messages to the globally available vscode window -
vscode.postMessage
- In Jetbrains, the GUI posts messages to the Tool Window browser using the injected
window.postJetbrainsMessage
(see below)
- Messages are sent to the IDE using an
- Receiving Messages
- a
useWebviewListener
hook can be used modularly by any component to listen to and respond to messages received from the IDE. This works by registering a listener to thewindow
that processes a message and then usesideMessenger.respond
to send a response back to the IDE
- a
- Since VSCode uses Typescript and does not need a compiled core binary, it can instantiate
Core
directly and message it in-process using anInProcessMessenger
. Messages to and from core use this, although, occasionally confusingly, the extension can also directly access core methods since it's just an instance ofCore
- VS Code sends and receives messages with the GUI using a
VsCodeWebviewProtocol
, which implementsrequest
,invoke
, etc. methods for thevscode.Webview
type VsCodeMessenger
is what connects everything - it registers listeners and implements pass-through functionality from theInProcessMessenger
to theVsCodeWebviewProtocol
, and hooks up IDE responses using an instance ofVsCodeIde
VsCodeExtension
houses everything, including the webview provider (ContinueGUIWebviewViewProvider, avscode.WebviewViewProvider
) that houses the webviewProtocol
- The Typescript core is compiled to a binary for use in the Kotlin/Java Jetbrains environment
- This Binary runs an Ipc (or Tcp for testing) server for communication with the extension (see
binary/src/index.ts
) Jetbrains communication can be understood from the vantage point of thecontinuePluginService
, which is initialized during continue plugin startup activity and registered to the globalServiceManager
. The plugin services gives three main communication channels access to eachother CoreMessenger
: uses Tcp or Ipc to send and recieve messages with the core. IDE-specific messages are forwarded to theideProtocol
and webview-specific messages are forwarded to the GUIContinueBrowser
: a wrapper around a JCEFBrowser which hosts the GUI and is used to communicate with the GUI.- Captures messages from the GUI by injecting a
window.postJetbrainsMessage
method on initialization, which the GUI specifically calls if on Jetbrains - Sends messages to the GUI by executing a javascript script within the
JCEFBrowser
which invokeswindow.postMessage
with the message contents - Forwards "pass through" events directly to the
coreMessenger
and sends the others to theideProtocol
- Initialized in the
ContinuePluginToolWindowFactory
- Captures messages from the GUI by injecting a
IdeProtocol
: provides responses to IDE-specific messages for thecoreMessenger
andcontinueBrowser
to use.- Since these 3 are set up in parallel there is no need for actual passing through the
IdeProtocol
- The Jetbrains IdeProtocol confusingly has an unused
send
method that sends to webview 😂