Skip to content

Commit 8843f1d

Browse files
authored
Merge pull request #3189 from Kilo-Org/mark/autotrigger-api
refactor: update AutoTriggerStrategy.getPrompts API to accept AutocompleteInput
2 parents f6b5e76 + e1a89c2 commit 8843f1d

File tree

9 files changed

+145
-312
lines changed

9 files changed

+145
-312
lines changed

src/services/ghost/GhostProvider.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { AutoTriggerStrategy } from "./strategies/AutoTriggerStrategy"
77
import { GhostModel } from "./GhostModel"
88
import { GhostWorkspaceEdit } from "./GhostWorkspaceEdit"
99
import { GhostDecorations } from "./GhostDecorations"
10-
import { GhostSuggestionContext } from "./types"
10+
import { GhostSuggestionContext, contextToAutocompleteInput, extractPrefixSuffix } from "./types"
1111
import { GhostStatusBar } from "./GhostStatusBar"
1212
import { GhostSuggestionsState } from "./GhostSuggestions"
1313
import { GhostCodeActionProvider } from "./GhostCodeActionProvider"
@@ -267,7 +267,19 @@ export class GhostProvider {
267267
this.isRequestCancelled = false
268268

269269
const context = await this.ghostContext.generate(initialContext)
270-
const { systemPrompt, userPrompt } = this.autoTriggerStrategy.getPrompts(context)
270+
271+
const autocompleteInput = contextToAutocompleteInput(context)
272+
273+
const position = context.range?.start ?? context.document.positionAt(0)
274+
const { prefix, suffix } = extractPrefixSuffix(context.document, position)
275+
const languageId = context.document.languageId
276+
277+
const { systemPrompt, userPrompt } = this.autoTriggerStrategy.getPrompts(
278+
autocompleteInput,
279+
prefix,
280+
suffix,
281+
languageId,
282+
)
271283
if (this.isRequestCancelled) {
272284
return
273285
}

src/services/ghost/__tests__/GhostModelPerformance.spec.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import * as vscode from "vscode"
22
import { describe, it, expect } from "vitest"
33
import { AutoTriggerStrategy } from "../strategies/AutoTriggerStrategy"
4-
import { MockWorkspace } from "./MockWorkspace"
54
import { ApiHandler, buildApiHandler } from "../../../api"
65
import { GhostModel } from "../GhostModel"
76
import { allowNetConnect } from "../../../vitest.setup"
7+
import { AutocompleteInput } from "../types"
8+
import crypto from "crypto"
89

910
const KEYS = {
1011
KILOCODE: null,
@@ -15,17 +16,19 @@ const KEYS = {
1516
describe("GhostModelPerformance", () => {
1617
const generatePrompt = (userInput: string) => {
1718
const autoTriggerStrategy = new AutoTriggerStrategy()
18-
const mockWorkspace = new MockWorkspace()
1919

2020
const testUri = vscode.Uri.parse("file:///example.ts")
21-
const document = mockWorkspace.addDocument(testUri, "")
2221

23-
const context = {
24-
userInput,
25-
document: document,
22+
const autocompleteInput: AutocompleteInput = {
23+
isUntitledFile: false,
24+
completionId: crypto.randomUUID(),
25+
filepath: testUri.fsPath,
26+
pos: { line: 0, character: 0 },
27+
recentlyVisitedRanges: [],
28+
recentlyEditedRanges: [],
2629
}
2730

28-
const { systemPrompt, userPrompt } = autoTriggerStrategy.getPrompts(context)
31+
const { systemPrompt, userPrompt } = autoTriggerStrategy.getPrompts(autocompleteInput, "", "", "typescript")
2932

3033
return { systemPrompt, suggestionPrompt: userPrompt }
3134
}

src/services/ghost/__tests__/GhostRecentOperations.spec.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as vscode from "vscode"
33
import { GhostContext } from "../GhostContext"
44
import { GhostDocumentStore } from "../GhostDocumentStore"
55
import { AutoTriggerStrategy } from "../strategies/AutoTriggerStrategy"
6-
import { GhostSuggestionContext } from "../types"
6+
import { GhostSuggestionContext, contextToAutocompleteInput } from "../types"
77
import { MockTextDocument } from "../../mocking/MockTextDocument"
88

99
// Mock vscode
@@ -115,8 +115,13 @@ describe("GhostRecentOperations", () => {
115115
expect(enrichedContext.recentOperations).toBeDefined()
116116
expect(enrichedContext.recentOperations?.length).toBeGreaterThan(0)
117117

118+
const autocompleteInput = contextToAutocompleteInput(enrichedContext)
119+
118120
// Generate prompt
119-
const { userPrompt } = autoTriggerStrategy.getPrompts(enrichedContext)
121+
const prefix = enrichedContext.document.getText()
122+
const suffix = ""
123+
const languageId = enrichedContext.document.languageId
124+
const { userPrompt } = autoTriggerStrategy.getPrompts(autocompleteInput, prefix, suffix, languageId)
120125

121126
// Verify that the prompt includes the recent operations section
122127
// The new strategy system uses "## Recent Typing" format
@@ -132,8 +137,13 @@ describe("GhostRecentOperations", () => {
132137
// Generate context
133138
const enrichedContext = await context.generate(suggestionContext)
134139

140+
const autocompleteInput = contextToAutocompleteInput(enrichedContext)
141+
135142
// Generate prompt
136-
const { userPrompt } = autoTriggerStrategy.getPrompts(enrichedContext)
143+
const prefix = enrichedContext.document.getText()
144+
const suffix = ""
145+
const languageId = enrichedContext.document.languageId
146+
const { userPrompt } = autoTriggerStrategy.getPrompts(autocompleteInput, prefix, suffix, languageId)
137147

138148
// Verify that the prompt does not include recent operations section
139149
// The current document content will still be in the prompt, so we should only check

src/services/ghost/strategies/AutoTriggerStrategy.ts

Lines changed: 38 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { GhostSuggestionContext, extractPrefix } from "../types"
1+
import { AutocompleteInput } from "../types"
22
import { CURSOR_MARKER } from "../ghostConstants"
3-
import { isCommentLine, extractComment, cleanComment } from "./CommentHelpers"
3+
import { isCommentLine, cleanComment } from "./CommentHelpers"
44
import type { TextDocument, Range } from "vscode"
55

66
export function getBaseSystemInstructions(): string {
@@ -55,15 +55,6 @@ export function addCursorMarker(document: TextDocument, range?: Range): string {
5555
return `${beforeCursor}${CURSOR_MARKER}${afterCursor}`
5656
}
5757

58-
export function formatDocumentWithCursor(document: TextDocument, range?: Range, languageId?: string): string {
59-
const lang = languageId || document.languageId
60-
const codeWithCursor = addCursorMarker(document, range)
61-
62-
return `\`\`\`${lang}
63-
${codeWithCursor}
64-
\`\`\``
65-
}
66-
6758
export class AutoTriggerStrategy {
6859
shouldTreatAsComment(prefix: string, languageId: string): boolean {
6960
const lines = prefix.split("\n")
@@ -79,22 +70,24 @@ export class AutoTriggerStrategy {
7970
}
8071
}
8172

82-
getPrompts(context: GhostSuggestionContext): {
73+
getPrompts(
74+
autocompleteInput: AutocompleteInput,
75+
prefix: string,
76+
suffix: string,
77+
languageId: string,
78+
): {
8379
systemPrompt: string
8480
userPrompt: string
8581
} {
86-
const prefix = extractPrefix(context)
87-
const languageId = context.document?.languageId || ""
88-
8982
if (this.shouldTreatAsComment(prefix, languageId)) {
9083
return {
9184
systemPrompt: this.getCommentsSystemInstructions(),
92-
userPrompt: this.getCommentsUserPrompt(context),
85+
userPrompt: this.getCommentsUserPrompt(prefix, suffix, languageId),
9386
}
9487
} else {
9588
return {
9689
systemPrompt: this.getSystemInstructions(),
97-
userPrompt: this.getUserPrompt(context),
90+
userPrompt: this.getUserPrompt(autocompleteInput, prefix, suffix, languageId),
9891
}
9992
}
10093
}
@@ -112,32 +105,29 @@ Provide non-intrusive completions after a typing pause. Be conservative and help
112105
/**
113106
* Build minimal prompt for auto-trigger
114107
*/
115-
getUserPrompt(context: GhostSuggestionContext): string {
108+
getUserPrompt(autocompleteInput: AutocompleteInput, prefix: string, suffix: string, languageId: string): string {
116109
let prompt = ""
117110

118-
// Start with recent typing context
119-
if (context.recentOperations && context.recentOperations.length > 0) {
111+
// Start with recent typing context from autocompleteInput
112+
if (autocompleteInput.recentlyEditedRanges && autocompleteInput.recentlyEditedRanges.length > 0) {
120113
prompt += "## Recent Typing\n"
121-
context.recentOperations.forEach((op, index) => {
122-
prompt += `${index + 1}. ${op.description}\n`
114+
autocompleteInput.recentlyEditedRanges.forEach((range, index) => {
115+
const description = `Edited ${range.filepath} at line ${range.range.start.line}`
116+
prompt += `${index + 1}. ${description}\n`
123117
})
124118
prompt += "\n"
125119
}
126120

127-
// Add current position
128-
if (context.range && context.document) {
129-
const line = context.range.start.line + 1
130-
const char = context.range.start.character + 1
131-
prompt += `## Current Position\n`
132-
prompt += `Line ${line}, Character ${char}\n\n`
133-
}
121+
// Add current position from autocompleteInput
122+
const line = autocompleteInput.pos.line + 1
123+
const char = autocompleteInput.pos.character + 1
124+
prompt += `## Current Position\n`
125+
prompt += `Line ${line}, Character ${char}\n\n`
134126

135127
// Add the full document with cursor marker
136-
if (context.document) {
137-
prompt += "## Full Code\n"
138-
prompt += formatDocumentWithCursor(context.document, context.range)
139-
prompt += "\n\n"
140-
}
128+
const codeWithCursor = `${prefix}${CURSOR_MARKER}${suffix}`
129+
prompt += "## Full Code\n"
130+
prompt += `\`\`\`${languageId}\n${codeWithCursor}\n\`\`\`\n\n`
141131

142132
// Add specific instructions
143133
prompt += "## Instructions\n"
@@ -189,23 +179,29 @@ Provide non-intrusive completions after a typing pause. Be conservative and help
189179
)
190180
}
191181

192-
getCommentsUserPrompt(context: GhostSuggestionContext): string {
193-
if (!context.document || !context.range) {
194-
return "No context available for comment-driven generation."
195-
}
182+
getCommentsUserPrompt(prefix: string, suffix: string, languageId: string): string {
183+
// Extract the comment from the prefix
184+
const lines = prefix.split("\n")
185+
const lastLine = lines[lines.length - 1]
186+
const previousLine = lines.length > 1 ? lines[lines.length - 2] : ""
196187

197-
const language = context.document.languageId
198-
const comment = cleanComment(extractComment(context.document, context.range.start.line), language)
188+
// Determine which line contains the comment
189+
const commentLine = isCommentLine(lastLine, languageId) ? lastLine : previousLine
190+
const comment = cleanComment(commentLine, languageId)
191+
192+
const codeWithCursor = `${prefix}${CURSOR_MARKER}${suffix}`
199193

200194
let prompt = `## Comment-Driven Development
201-
- Language: ${language}
195+
- Language: ${languageId}
202196
- Comment to Implement:
203197
\`\`\`
204198
${comment}
205199
\`\`\`
206200
207201
## Full Code
208-
${formatDocumentWithCursor(context.document, context.range)}
202+
\`\`\`${languageId}
203+
${codeWithCursor}
204+
\`\`\`
209205
210206
## Instructions
211207
Generate code that implements the functionality described in the comment.

src/services/ghost/strategies/CommentHelpers.ts

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -38,56 +38,6 @@ export function isCommentLine(line: string, languageId: string): boolean {
3838
return false
3939
}
4040

41-
export function extractComment(document: TextDocument, currentLine: number): string {
42-
let comment = ""
43-
44-
// Get the comment (could be multi-line)
45-
let commentStartLine = currentLine
46-
let commentEndLine = currentLine
47-
48-
// Check if current line is a comment
49-
const currentLineText = document.lineAt(currentLine).text
50-
if (isCommentLine(currentLineText.trim(), document.languageId)) {
51-
comment = currentLineText.trim()
52-
53-
// Check for multi-line comments above
54-
let line = currentLine - 1
55-
while (line >= 0) {
56-
const lineText = document.lineAt(line).text.trim()
57-
if (isCommentLine(lineText, document.languageId)) {
58-
comment = lineText + "\n" + comment
59-
commentStartLine = line
60-
line--
61-
} else {
62-
break
63-
}
64-
}
65-
66-
// Check for multi-line comments below
67-
line = currentLine + 1
68-
while (line < document.lineCount) {
69-
const lineText = document.lineAt(line).text.trim()
70-
if (isCommentLine(lineText, document.languageId)) {
71-
comment = comment + "\n" + lineText
72-
commentEndLine = line
73-
line++
74-
} else {
75-
break
76-
}
77-
}
78-
} else if (currentLine > 0) {
79-
// Check previous line for comment
80-
const prevLineText = document.lineAt(currentLine - 1).text
81-
if (isCommentLine(prevLineText.trim(), document.languageId)) {
82-
comment = prevLineText.trim()
83-
commentStartLine = currentLine - 1
84-
commentEndLine = currentLine - 1
85-
}
86-
}
87-
88-
return comment
89-
}
90-
9141
/**
9242
* Cleans comment text by removing comment syntax
9343
*/

0 commit comments

Comments
 (0)