refactor(vscode): drop chat-completion fallback in chat textarea autocomplete

Both supported autocomplete models (Codestral, Mercury) expose FIM, and
AutocompleteModel.supportsFim() unconditionally returns true. The non-FIM
branch in ChatTextAreaAutocomplete together with the getChatSystemPrompt
/ getChatUserPrompt helpers was never reached.

Also removes the accompanying orphaned spec that imported paths that no
longer exist (core/config/ProviderSettingsManager, api/transform/stream).
This commit is contained in:
kiloconnect[bot]
2026-04-20 15:22:07 +00:00
parent 8175daeabc
commit b647f151a7
2 changed files with 3 additions and 129 deletions
@@ -98,22 +98,9 @@ export class ChatTextAreaAutocomplete {
let response = ""
try {
// Use FIM if supported, otherwise fall back to chat-based completion
if (this.model.supportsFim()) {
await this.model.generateFimResponse(prefix, suffix, (chunk) => {
response += chunk
})
} else {
// Fall back to chat-based completion for models without FIM support
const systemPrompt = this.getChatSystemPrompt()
const userPrompt = this.getChatUserPrompt(prefix)
await this.model.generateResponse(systemPrompt, userPrompt, (chunk) => {
if (chunk.type === "text") {
response += chunk.text
}
})
}
await this.model.generateFimResponse(prefix, suffix, (chunk) => {
response += chunk
})
const latencyMs = Date.now() - startTime
@@ -153,35 +140,6 @@ export class ChatTextAreaAutocomplete {
}
}
/**
* Get system prompt for chat-based completion
*/
private getChatSystemPrompt(): string {
return `You are an intelligent chat completion assistant. Your task is to complete the user's message naturally based on the provided context.
## RULES
- Provide a natural, conversational completion
- Be concise - typically 1-15 words
- Match the user's tone and style
- Use context from visible code if relevant
- NEVER repeat what the user already typed
- NEVER start with comments (//, /*, #)
- If the user is in the middle of typing a word (e.g., "hel"), include the COMPLETE word in your response (e.g., "hello world" not just "lo world")
- This allows proper prefix matching to remove the overlap correctly
- Return ONLY the completion text, no explanations or formatting`
}
/**
* Get user prompt for chat-based completion
*/
private getChatUserPrompt(prefix: string): string {
return `${prefix}
TASK: Complete the user's message naturally.
- If the user is mid-word (e.g., typed "hel"), return the COMPLETE word (e.g., "hello world") so prefix matching can work correctly
- Return ONLY the completion text (what comes next), no explanations.`
}
private async buildPrefix(userText: string, visibleCodeContext?: VisibleCodeContext): Promise<string> {
return buildChatPrefix(userText, visibleCodeContext?.editors)
}
@@ -1,84 +0,0 @@
import { ChatTextAreaAutocomplete } from "../ChatTextAreaAutocomplete"
import { ProviderSettingsManager } from "../../../../core/config/ProviderSettingsManager"
import { AutocompleteModel } from "../../AutocompleteModel"
import { ApiStreamChunk } from "../../../../api/transform/stream"
describe("ChatTextAreaAutocomplete", () => {
let autocomplete: ChatTextAreaAutocomplete
let mockProviderSettingsManager: ProviderSettingsManager
beforeEach(() => {
mockProviderSettingsManager = {} as ProviderSettingsManager
autocomplete = new ChatTextAreaAutocomplete(mockProviderSettingsManager)
})
describe("getCompletion", () => {
it("should work with non-FIM models using chat-based completion", async () => {
// Setup: Model without FIM support (like Mistral)
const mockModel = new AutocompleteModel()
vi.spyOn(mockModel, "hasValidCredentials").mockReturnValue(true)
vi.spyOn(mockModel, "supportsFim").mockReturnValue(false)
vi.spyOn(mockModel, "generateResponse").mockImplementation(async (systemPrompt, userPrompt, onChunk) => {
// Simulate streaming chat response
const chunks: ApiStreamChunk[] = [{ type: "text", text: "write a function" }]
for (const chunk of chunks) {
onChunk(chunk)
}
return {
cost: 0,
inputTokens: 15,
outputTokens: 8,
cacheWriteTokens: 0,
cacheReadTokens: 0,
}
})
// @ts-expect-error - accessing private property for test
autocomplete.model = mockModel
const result = await autocomplete.getCompletion("How to ")
expect(mockModel.generateResponse).toHaveBeenCalled()
expect(result.suggestion).toBe("write a function")
})
})
describe("cleanSuggestion", () => {
it("should filter code patterns (comments, preprocessor)", () => {
// Comments - filtered by the regex check in cleanSuggestion
expect(autocomplete.cleanSuggestion("// comment", "")).toBe("")
expect(autocomplete.cleanSuggestion("/* comment", "")).toBe("")
expect(autocomplete.cleanSuggestion("* something", "")).toBe("")
// Code patterns
expect(autocomplete.cleanSuggestion("#include", "")).toBe("")
expect(autocomplete.cleanSuggestion("# Header", "")).toBe("")
})
it("should filter empty content", () => {
// Empty content is filtered by postprocessAutocompleteSuggestion
expect(autocomplete.cleanSuggestion("", "")).toBe("")
})
it("should accept natural language suggestions", () => {
expect(autocomplete.cleanSuggestion("Hello world", "")).toBe("Hello world")
expect(autocomplete.cleanSuggestion("Can you help me", "")).toBe("Can you help me")
expect(autocomplete.cleanSuggestion("test123", "")).toBe("test123")
expect(autocomplete.cleanSuggestion("What's up?", "")).toBe("What's up?")
})
it("should accept symbols in middle of text", () => {
expect(autocomplete.cleanSuggestion("Text with # in middle", "")).toBe("Text with # in middle")
expect(autocomplete.cleanSuggestion("Hello // but not a comment", "")).toBe("Hello // but not a comment")
})
it("should truncate at first newline", () => {
expect(autocomplete.cleanSuggestion("First line\nSecond line", "")).toBe("First line")
})
it("should remove prefix overlap", () => {
expect(autocomplete.cleanSuggestion("Hello world", "Hello ")).toBe("world")
})
})
})