Skip to content

Commit 035a0de

Browse files
committed
feat: Add experimental Continue.dev-based autocomplete as alternative to classic autocomplete
This commit introduces a new experimental autocomplete system based on Continue.dev as an alternative to the existing classic autocomplete provider. The feature is only available in development mode to ensure it's not accidentally enabled in production. Changes: - Moved autocomplete implementation from src/services/autocomplete/ to src/services/ghost/new-auto-complete/ - Renamed AutocompleteProvider to NewAutocompleteProvider and AutocompleteModel to NewAutocompleteModel - Integrated new autocomplete provider into GhostServiceManager with conditional loading - Added UI checkbox in settings (dev-only) to toggle between classic and new autocomplete - Removed VSCode configuration setting in favor of internal state management - Added proper cleanup and disposal when switching between providers File changes: - Created src/services/ghost/new-auto-complete/NewAutocompleteProvider.ts - Created src/services/ghost/new-auto-complete/NewAutocompleteModel.ts - Modified src/services/ghost/GhostServiceManager.ts to support dual providers - Modified src/extension.ts to remove old autocomplete imports - Modified webview-ui/src/components/kilocode/settings/GhostServiceSettings.tsx to add dev-only toggle - Modified packages/types/src/kilocode/kilocode.ts to include useNewAutocomplete field - Removed src/services/autocomplete/ directory and all its contents The new autocomplete: - Uses Continue.dev's ContinueCompletionProvider internally - Supports Mistral, KiloCode, and OpenRouter providers - Maintains backward compatibility with classic autocomplete as default - Only visible in development mode with [DEV ONLY] label Testing: - All existing tests pass - TypeScript compilation successful for both backend and UI - No breaking changes to existing functionality
1 parent c091e02 commit 035a0de

File tree

9 files changed

+123
-99
lines changed

9 files changed

+123
-99
lines changed

packages/types/src/kilocode/kilocode.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const ghostServiceSettingsSchema = z
1313
enableQuickInlineTaskKeybinding: z.boolean().optional(),
1414
enableSmartInlineTaskKeybinding: z.boolean().optional(),
1515
showGutterAnimation: z.boolean().optional(),
16+
useNewAutocomplete: z.boolean().optional(),
1617
provider: z.string().optional(),
1718
model: z.string().optional(),
1819
})

src/extension.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ import { initializeI18n } from "./i18n"
4545
import { registerGhostProvider } from "./services/ghost" // kilocode_change
4646
import { registerMainThreadForwardingLogger } from "./utils/fowardingLogger" // kilocode_change
4747
import { getKiloCodeWrapperProperties } from "./core/kilocode/wrapper" // kilocode_change
48-
import { registerAutocompleteProvider } from "./services/autocomplete" // kilocode_change
4948

5049
/**
5150
* Built using https://github.com/microsoft/vscode-webview-ui-toolkit
@@ -322,8 +321,6 @@ export async function activate(context: vscode.ExtensionContext) {
322321
if (!kiloCodeWrapped) {
323322
// Only use autocomplete in VS Code
324323
registerGhostProvider(context, provider)
325-
// Experimental
326-
// registerAutocompleteProvider(context, provider)
327324
} else {
328325
// Only foward logs in Jetbrains
329326
registerMainThreadForwardingLogger(context)

src/services/autocomplete/index.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/services/ghost/GhostServiceManager.ts

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { GhostModel } from "./GhostModel"
66
import { GhostStatusBar } from "./GhostStatusBar"
77
import { GhostCodeActionProvider } from "./GhostCodeActionProvider"
88
import { GhostInlineCompletionProvider } from "./classic-auto-complete/GhostInlineCompletionProvider"
9+
import { NewAutocompleteProvider } from "./new-auto-complete/NewAutocompleteProvider"
910
import { GhostServiceSettings, TelemetryEventName } from "@roo-code/types"
1011
import { ContextProxy } from "../../core/config/ContextProxy"
1112
import { ProviderSettingsManager } from "../../core/config/ProviderSettingsManager"
@@ -37,6 +38,7 @@ export class GhostServiceManager {
3738
// VSCode Providers
3839
public codeActionProvider: GhostCodeActionProvider
3940
public inlineCompletionProvider: GhostInlineCompletionProvider
41+
private newAutocompleteProvider: NewAutocompleteProvider | null = null
4042
private inlineCompletionProviderDisposable: vscode.Disposable | null = null
4143

4244
private ignoreController?: Promise<RooIgnoreController>
@@ -123,19 +125,37 @@ export class GhostServiceManager {
123125

124126
private async updateInlineCompletionProviderRegistration() {
125127
const shouldBeRegistered = this.settings?.enableAutoTrigger ?? false
128+
const useNewAutocomplete = this.settings?.useNewAutocomplete ?? false
126129

127-
if (shouldBeRegistered && !this.inlineCompletionProviderDisposable) {
128-
// Register the provider
129-
this.inlineCompletionProviderDisposable = vscode.languages.registerInlineCompletionItemProvider(
130-
"*",
131-
this.inlineCompletionProvider,
132-
)
133-
this.context.subscriptions.push(this.inlineCompletionProviderDisposable)
134-
} else if (!shouldBeRegistered && this.inlineCompletionProviderDisposable) {
135-
// Deregister the provider
130+
// First, dispose any existing registration
131+
if (this.inlineCompletionProviderDisposable) {
136132
this.inlineCompletionProviderDisposable.dispose()
137133
this.inlineCompletionProviderDisposable = null
138134
}
135+
136+
// Dispose new autocomplete provider if switching away from it
137+
if (!useNewAutocomplete && this.newAutocompleteProvider) {
138+
this.newAutocompleteProvider.dispose()
139+
this.newAutocompleteProvider = null
140+
}
141+
142+
if (shouldBeRegistered) {
143+
if (useNewAutocomplete) {
144+
// Initialize new autocomplete provider if not already created
145+
if (!this.newAutocompleteProvider) {
146+
this.newAutocompleteProvider = new NewAutocompleteProvider(this.context, this.cline)
147+
await this.newAutocompleteProvider.load()
148+
}
149+
// New autocomplete provider registers itself internally
150+
} else {
151+
// Register classic provider
152+
this.inlineCompletionProviderDisposable = vscode.languages.registerInlineCompletionItemProvider(
153+
"*",
154+
this.inlineCompletionProvider,
155+
)
156+
this.context.subscriptions.push(this.inlineCompletionProviderDisposable)
157+
}
158+
}
139159
}
140160

141161
public async disable() {
@@ -272,6 +292,15 @@ export class GhostServiceManager {
272292
return
273293
}
274294

295+
// Check if using new autocomplete
296+
const useNewAutocomplete = this.settings?.useNewAutocomplete ?? false
297+
298+
if (useNewAutocomplete) {
299+
// New autocomplete doesn't support manual code suggestion yet
300+
// Just return for now
301+
return
302+
}
303+
275304
// Ensure model is loaded
276305
if (!this.model.loaded) {
277306
await this.load()
@@ -416,7 +445,13 @@ export class GhostServiceManager {
416445

417446
public cancelRequest() {
418447
this.stopProcessing()
419-
this.inlineCompletionProvider.cancelRequest()
448+
// Check which provider is active and cancel appropriately
449+
const useNewAutocomplete = this.settings?.useNewAutocomplete ?? false
450+
if (useNewAutocomplete) {
451+
// New autocomplete doesn't have a cancel method yet
452+
} else {
453+
this.inlineCompletionProvider.cancelRequest()
454+
}
420455
}
421456

422457
/**
@@ -434,6 +469,12 @@ export class GhostServiceManager {
434469
this.inlineCompletionProviderDisposable = null
435470
}
436471

472+
// Dispose new autocomplete provider if it exists
473+
if (this.newAutocompleteProvider) {
474+
this.newAutocompleteProvider.dispose()
475+
this.newAutocompleteProvider = null
476+
}
477+
437478
this.disposeIgnoreController()
438479

439480
GhostServiceManager.instance = null // Reset singleton

src/services/autocomplete/AutocompleteModel.ts renamed to src/services/ghost/new-auto-complete/NewAutocompleteModel.ts

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ import {
66
ProviderSettings,
77
ProviderSettingsEntry,
88
} from "@roo-code/types"
9-
import { ApiHandler, buildApiHandler } from "../../api"
10-
import { ProviderSettingsManager } from "../../core/config/ProviderSettingsManager"
11-
import { OpenRouterHandler } from "../../api/providers"
12-
import { ApiStreamChunk } from "../../api/transform/stream"
13-
import { ILLM, LLMOptions } from "../continuedev/core/index.js"
14-
import { DEFAULT_AUTOCOMPLETE_OPTS } from "../continuedev/core/util/parameters.js"
15-
import Mistral from "../continuedev/core/llm/llms/Mistral"
16-
import OpenRouter from "../continuedev/core/llm/llms/OpenRouter"
17-
import KiloCode from "../continuedev/core/llm/llms/KiloCode"
9+
import { ApiHandler, buildApiHandler } from "../../../api"
10+
import { ProviderSettingsManager } from "../../../core/config/ProviderSettingsManager"
11+
import { OpenRouterHandler } from "../../../api/providers"
12+
import { ApiStreamChunk } from "../../../api/transform/stream"
13+
import { ILLM, LLMOptions } from "../../continuedev/core/index.js"
14+
import { DEFAULT_AUTOCOMPLETE_OPTS } from "../../continuedev/core/util/parameters.js"
15+
import Mistral from "../../continuedev/core/llm/llms/Mistral"
16+
import OpenRouter from "../../continuedev/core/llm/llms/OpenRouter"
17+
import KiloCode from "../../continuedev/core/llm/llms/KiloCode"
1818

1919
export const AUTOCOMPLETE_PROVIDER_MODELS = {
2020
mistral: "codestral-2501",
@@ -23,7 +23,7 @@ export const AUTOCOMPLETE_PROVIDER_MODELS = {
2323
bedrock: "mistral.codestral-2501-v1:0",
2424
} as const
2525

26-
export class AutocompleteModel {
26+
export class NewAutocompleteModel {
2727
private apiHandler: ApiHandler | null = null
2828
private profile: ProviderSettings | null = null
2929
public loaded = false
@@ -95,7 +95,7 @@ export class AutocompleteModel {
9595
*/
9696
public getILLM(): ILLM | null {
9797
if (!this.profile?.apiProvider) {
98-
console.warn("[AutocompleteModel] No profile loaded")
98+
console.warn("[NewAutocompleteModel] No profile loaded")
9999
return null
100100
}
101101

@@ -105,7 +105,7 @@ export class AutocompleteModel {
105105
// Extract provider-specific configuration
106106
const config = this.extractProviderConfig()
107107
if (!config) {
108-
console.warn(`[AutocompleteModel] Failed to extract config for provider: ${provider}`)
108+
console.warn(`[NewAutocompleteModel] Failed to extract config for provider: ${provider}`)
109109
return null
110110
}
111111

@@ -140,7 +140,7 @@ export class AutocompleteModel {
140140
// Create appropriate LLM instance based on provider
141141
return this.createLLMInstance(provider, llmOptions)
142142
} catch (error) {
143-
console.error(`[AutocompleteModel] Error creating ILLM for provider ${provider}:`, error)
143+
console.error(`[NewAutocompleteModel] Error creating ILLM for provider ${provider}:`, error)
144144
return null
145145
}
146146
}
@@ -164,7 +164,7 @@ export class AutocompleteModel {
164164
switch (provider) {
165165
case "mistral":
166166
if (!this.profile.mistralApiKey) {
167-
console.warn("[AutocompleteModel] Missing Mistral API key")
167+
console.warn("[NewAutocompleteModel] Missing Mistral API key")
168168
return null
169169
}
170170
return {
@@ -175,7 +175,7 @@ export class AutocompleteModel {
175175

176176
case "kilocode":
177177
if (!this.profile.kilocodeToken) {
178-
console.warn("[AutocompleteModel] Missing Kilocode token")
178+
console.warn("[NewAutocompleteModel] Missing Kilocode token")
179179
return null
180180
}
181181
return {
@@ -187,7 +187,7 @@ export class AutocompleteModel {
187187

188188
case "openrouter":
189189
if (!this.profile.openRouterApiKey) {
190-
console.warn("[AutocompleteModel] Missing OpenRouter API key")
190+
console.warn("[NewAutocompleteModel] Missing OpenRouter API key")
191191
return null
192192
}
193193
return {
@@ -199,11 +199,11 @@ export class AutocompleteModel {
199199
case "bedrock":
200200
// Bedrock uses AWS credentials, not a simple API key
201201
// For now, return null as it requires more complex setup
202-
console.warn("[AutocompleteModel] Bedrock provider not yet supported for autocomplete")
202+
console.warn("[NewAutocompleteModel] Bedrock provider not yet supported for autocomplete")
203203
return null
204204

205205
default:
206-
console.warn(`[AutocompleteModel] Unsupported provider: ${provider}`)
206+
console.warn(`[NewAutocompleteModel] Unsupported provider: ${provider}`)
207207
return null
208208
}
209209
}

src/services/autocomplete/AutocompleteProvider.ts renamed to src/services/ghost/new-auto-complete/NewAutocompleteProvider.ts

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,30 @@
11
import * as vscode from "vscode"
2-
import { AutocompleteModel } from "./AutocompleteModel"
3-
import {
4-
AUTOCOMPLETE_PROVIDER_MODELS,
5-
AutocompleteProviderKey,
6-
GhostServiceSettings,
7-
modelIdKeysByProvider,
8-
ProviderSettingsEntry,
9-
} from "@roo-code/types"
10-
import { ContextProxy } from "../../core/config/ContextProxy"
11-
import { ProviderSettingsManager } from "../../core/config/ProviderSettingsManager"
12-
import { ClineProvider } from "../../core/webview/ClineProvider"
13-
import { MinimalConfigProvider } from "../continuedev/core/autocomplete/MinimalConfig"
14-
import { VsCodeIde } from "../continuedev/core/vscode-test-harness/src/VSCodeIde"
15-
import { ContinueCompletionProvider } from "../continuedev/core/vscode-test-harness/src/autocomplete/completionProvider"
16-
import OpenRouter from "../continuedev/core/llm/llms/OpenRouter"
17-
18-
export class AutocompleteProvider {
2+
import { NewAutocompleteModel } from "./NewAutocompleteModel"
3+
import { GhostServiceSettings } from "@roo-code/types"
4+
import { ContextProxy } from "../../../core/config/ContextProxy"
5+
import { ProviderSettingsManager } from "../../../core/config/ProviderSettingsManager"
6+
import { ClineProvider } from "../../../core/webview/ClineProvider"
7+
import { MinimalConfigProvider } from "../../continuedev/core/autocomplete/MinimalConfig"
8+
import { VsCodeIde } from "../../continuedev/core/vscode-test-harness/src/VSCodeIde"
9+
import { ContinueCompletionProvider } from "../../continuedev/core/vscode-test-harness/src/autocomplete/completionProvider"
10+
11+
export class NewAutocompleteProvider {
1912
private completionProviderDisposable: vscode.Disposable | null = null
20-
private model: AutocompleteModel
13+
private model: NewAutocompleteModel
2114
private providerSettingsManager: ProviderSettingsManager
2215
private settings: GhostServiceSettings | null = null
2316

24-
private enabled: boolean = true
25-
private taskId: string | null = null
26-
private isProcessing: boolean = false
27-
private isRequestCancelled: boolean = false
28-
29-
// VSCode Providers
30-
public inlineCompletionProvider: any
31-
3217
constructor(
3318
private context: vscode.ExtensionContext,
3419
private cline: ClineProvider,
3520
) {
3621
// Register Internal Components
3722
this.providerSettingsManager = new ProviderSettingsManager(context)
38-
this.model = new AutocompleteModel()
23+
this.model = new NewAutocompleteModel()
3924

4025
void this.load()
4126
}
4227

43-
// Instance is created and managed by the registration function
44-
4528
// Settings Management
4629
private loadSettings() {
4730
const state = ContextProxy.instance.getValues()
@@ -74,7 +57,7 @@ export class AutocompleteProvider {
7457
// The model.reload() has already loaded the profile, so we can get the ILLM
7558
const llm = this.model.getILLM()
7659
if (!llm) {
77-
console.warn("[AutocompleteProvider] No valid autocomplete provider found")
60+
console.warn("[NewAutocompleteProvider] No valid autocomplete provider found")
7861
return
7962
}
8063

@@ -94,9 +77,9 @@ export class AutocompleteProvider {
9477
)
9578
this.context.subscriptions.push(this.completionProviderDisposable)
9679

97-
console.log("[AutocompleteProvider] Successfully registered autocomplete")
80+
console.log("[NewAutocompleteProvider] Successfully registered autocomplete")
9881
} catch (error) {
99-
console.error("[AutocompleteProvider] Error loading code completion:", error)
82+
console.error("[NewAutocompleteProvider] Error loading code completion:", error)
10083
}
10184
}
10285

@@ -146,7 +129,7 @@ export class AutocompleteProvider {
146129
}
147130

148131
/**
149-
* Dispose of all resources used by the AutocompleteProvider
132+
* Dispose of all resources used by the NewAutocompleteProvider
150133
*/
151134
public dispose(): void {
152135
if (this.completionProviderDisposable) {

src/services/autocomplete/__tests__/AutocompleteModel.spec.ts renamed to src/services/ghost/new-auto-complete/__tests__/NewAutocompleteModel.spec.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import { describe, it, expect, beforeEach, vi } from "vitest"
2-
import { AutocompleteModel } from "../AutocompleteModel"
2+
import { NewAutocompleteModel } from "../NewAutocompleteModel"
33
import { ProviderSettings } from "@roo-code/types"
4-
import Mistral from "../../continuedev/core/llm/llms/Mistral"
5-
import { OpenAI } from "../../continuedev/core/llm/llms/OpenAI"
4+
import Mistral from "../../../continuedev/core/llm/llms/Mistral"
5+
import { OpenAI } from "../../../continuedev/core/llm/llms/OpenAI"
66

77
// Mock the LLM classes
8-
vi.mock("../../continuedev/core/llm/llms/Mistral")
9-
vi.mock("../../continuedev/core/llm/llms/OpenAI")
8+
vi.mock("../../../continuedev/core/llm/llms/Mistral")
9+
vi.mock("../../../continuedev/core/llm/llms/OpenAI")
1010

11-
describe("AutocompleteModel", () => {
12-
let model: AutocompleteModel
11+
describe("NewAutocompleteModel", () => {
12+
let model: NewAutocompleteModel
1313

1414
beforeEach(() => {
15-
model = new AutocompleteModel()
15+
model = new NewAutocompleteModel()
1616
vi.clearAllMocks()
1717
})
1818

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { NewAutocompleteProvider } from "./NewAutocompleteProvider"
2+
export { NewAutocompleteModel } from "./NewAutocompleteModel"

0 commit comments

Comments
 (0)