Compare commits
8 Commits
@continued
...
v1.2.8-vsc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a69daa3190 | ||
|
|
d68d0f8686 | ||
|
|
758320a341 | ||
|
|
b13f89745d | ||
|
|
53b2a7d794 | ||
|
|
2579dd5d4f | ||
|
|
be306b8877 | ||
|
|
d6f3a90690 |
@@ -268,6 +268,8 @@ export class CompletionProvider {
|
||||
gitRepo: await this.ide.getRepoName(helper.filepath),
|
||||
uniqueId: await this.ide.getUniqueId(),
|
||||
timestamp: new Date().toISOString(),
|
||||
profileType:
|
||||
this.configHandler.currentProfile?.profileDescription.profileType,
|
||||
...helper.options,
|
||||
};
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ function isBlank(completion: string): boolean {
|
||||
|
||||
/**
|
||||
* Removes markdown code block delimiters from completion.
|
||||
* Removes the first line if it starts with "```" and the last line if it is exactly "```".
|
||||
* Removes the first line if it contains only backticks and the last line if it contains only backticks.
|
||||
*/
|
||||
function removeBackticks(completion: string): string {
|
||||
const lines = completion.split("\n");
|
||||
@@ -66,14 +66,18 @@ function removeBackticks(completion: string): string {
|
||||
let startIdx = 0;
|
||||
let endIdx = lines.length;
|
||||
|
||||
// Remove first line if it starts with ```
|
||||
if (lines[0].trimStart().startsWith("```")) {
|
||||
// Remove first line if it contains only backticks (one or more)
|
||||
const firstLineTrimmed = lines[0].trim();
|
||||
if (firstLineTrimmed.length > 0 && /^`+$/.test(firstLineTrimmed)) {
|
||||
startIdx = 1;
|
||||
}
|
||||
|
||||
// Remove last line if it is exactly ```
|
||||
if (lines.length > startIdx && lines[lines.length - 1].trim() === "```") {
|
||||
endIdx = lines.length - 1;
|
||||
// Remove last line if it contains only backticks (one or more)
|
||||
if (lines.length > startIdx) {
|
||||
const lastLineTrimmed = lines[lines.length - 1].trim();
|
||||
if (lastLineTrimmed.length > 0 && /^`+$/.test(lastLineTrimmed)) {
|
||||
endIdx = lines.length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If we removed lines, return the modified completion
|
||||
|
||||
@@ -119,6 +119,7 @@ export class AutocompleteLoggingService {
|
||||
time: restOfOutcome.time,
|
||||
useRecentlyEdited: restOfOutcome.useRecentlyEdited,
|
||||
numLines: restOfOutcome.numLines,
|
||||
profileType: restOfOutcome.profileType,
|
||||
};
|
||||
|
||||
outcome.enabledStaticContextualization
|
||||
|
||||
@@ -43,4 +43,5 @@ export interface AutocompleteOutcome extends TabAutocompleteOptions {
|
||||
uniqueId: string;
|
||||
timestamp: string;
|
||||
enabledStaticContextualization?: boolean;
|
||||
profileType?: "local" | "platform" | "control-plane";
|
||||
}
|
||||
|
||||
@@ -537,12 +537,19 @@ export class ConfigHandler {
|
||||
// Track config loading telemetry
|
||||
const endTime = performance.now();
|
||||
const duration = endTime - startTime;
|
||||
void Telemetry.capture("config_reload", {
|
||||
|
||||
const profileDescription = this.currentProfile.profileDescription;
|
||||
const telemetryData: Record<string, any> = {
|
||||
duration,
|
||||
reason,
|
||||
totalConfigLoads: this.totalConfigReloads,
|
||||
configLoadInterrupted,
|
||||
});
|
||||
profileType: profileDescription.profileType,
|
||||
isPersonalOrg: this.currentOrg?.id === this.PERSONAL_ORG_DESC.id,
|
||||
errorCount: errors.length,
|
||||
};
|
||||
|
||||
void Telemetry.capture("config_reload", telemetryData);
|
||||
|
||||
return {
|
||||
config,
|
||||
|
||||
@@ -95,9 +95,6 @@ export class NextEditLoggingService {
|
||||
outcome.accepted = true;
|
||||
outcome.aborted = false;
|
||||
this.logNextEditOutcome(outcome);
|
||||
if (outcome.requestId) {
|
||||
void this.logAcceptReject(outcome.requestId, true);
|
||||
}
|
||||
this._outcomes.delete(completionId);
|
||||
return outcome;
|
||||
}
|
||||
@@ -116,9 +113,6 @@ export class NextEditLoggingService {
|
||||
outcome.accepted = false;
|
||||
outcome.aborted = false;
|
||||
this.logNextEditOutcome(outcome);
|
||||
if (outcome.requestId) {
|
||||
void this.logAcceptReject(outcome.requestId, false);
|
||||
}
|
||||
this._outcomes.delete(completionId);
|
||||
return outcome;
|
||||
}
|
||||
@@ -151,9 +145,6 @@ export class NextEditLoggingService {
|
||||
outcome.accepted = false;
|
||||
outcome.aborted = false;
|
||||
this.logNextEditOutcome(outcome);
|
||||
if (outcome.requestId) {
|
||||
void this.logAcceptReject(outcome.requestId, false);
|
||||
}
|
||||
this._logRejectionTimeouts.delete(completionId);
|
||||
this._outcomes.delete(completionId);
|
||||
}, COUNT_COMPLETION_REJECTED_AFTER);
|
||||
@@ -197,44 +188,15 @@ export class NextEditLoggingService {
|
||||
this._logRejectionTimeouts.delete(completionId);
|
||||
}
|
||||
|
||||
// If we have the full outcome, log it as aborted.
|
||||
// Only log if the completion was displayed to the user.
|
||||
// This aligns with Autocomplete behavior and prevents logging
|
||||
// of cancelled requests that never reached the user.
|
||||
if (this._outcomes.has(completionId)) {
|
||||
const outcome = this._outcomes.get(completionId)!;
|
||||
outcome.accepted = false;
|
||||
// outcome.accepted = false;
|
||||
outcome.aborted = true;
|
||||
this.logNextEditOutcome(outcome);
|
||||
this._outcomes.delete(completionId);
|
||||
} else {
|
||||
// Log minimal abort event for requests that never got displayed.
|
||||
const pendingData = this._pendingCompletions.get(completionId);
|
||||
|
||||
const minimalAbortOutcome: Partial<NextEditOutcome> = {
|
||||
completionId,
|
||||
accepted: false,
|
||||
aborted: true,
|
||||
timestamp: Date.now(),
|
||||
uniqueId: completionId,
|
||||
elapsed: pendingData ? Date.now() - pendingData.startTime : 0,
|
||||
modelName: pendingData?.modelName || "unknown",
|
||||
modelProvider: pendingData?.modelProvider || "unknown",
|
||||
fileUri: pendingData?.filepath || "unknown",
|
||||
|
||||
// Empty/default values for fields we don't have.
|
||||
completion: "",
|
||||
prompt: "",
|
||||
userEdits: "",
|
||||
userExcerpts: "",
|
||||
originalEditableRange: "",
|
||||
workspaceDirUri: "",
|
||||
cursorPosition: { line: -1, character: -1 },
|
||||
finalCursorPosition: { line: -1, character: -1 },
|
||||
editableRegionStartLine: -1,
|
||||
editableRegionEndLine: -1,
|
||||
diffLines: [],
|
||||
completionOptions: {},
|
||||
};
|
||||
|
||||
this.logNextEditOutcome(minimalAbortOutcome as NextEditOutcome);
|
||||
}
|
||||
|
||||
// Clean up.
|
||||
@@ -255,6 +217,9 @@ export class NextEditLoggingService {
|
||||
});
|
||||
|
||||
// const { prompt, completion, prefix, suffix, ...restOfOutcome } = outcome;
|
||||
if (outcome.requestId && outcome.accepted !== undefined) {
|
||||
void this.logAcceptReject(outcome.requestId, outcome.accepted);
|
||||
}
|
||||
void Telemetry.capture("nextEditOutcome", outcome, true);
|
||||
}
|
||||
|
||||
@@ -268,7 +233,7 @@ export class NextEditLoggingService {
|
||||
}
|
||||
|
||||
const controlPlaneEnv = getControlPlaneEnvSync("production");
|
||||
await fetchwithRequestOptions(
|
||||
const resp = await fetchwithRequestOptions(
|
||||
new URL("model-proxy/v1/feedback", controlPlaneEnv.CONTROL_PLANE_URL),
|
||||
{
|
||||
method: "POST",
|
||||
|
||||
@@ -140,7 +140,7 @@ export class PrefetchQueue {
|
||||
const count = Math.min(3, this.processedQueue.length);
|
||||
const firstThree = this.processedQueue.slice(0, count);
|
||||
firstThree.forEach((item, index) => {
|
||||
console.log(
|
||||
console.debug(
|
||||
`Item ${index + 1}: ${item.location.range.start.line} to ${item.location.range.end.line}`,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ import { ContextRetrievalService } from "../autocomplete/context/ContextRetrieva
|
||||
|
||||
import { BracketMatchingService } from "../autocomplete/filtering/BracketMatchingService.js";
|
||||
import { CompletionStreamer } from "../autocomplete/generation/CompletionStreamer.js";
|
||||
import { postprocessCompletion } from "../autocomplete/postprocessing/index.js";
|
||||
import { shouldPrefilter } from "../autocomplete/prefiltering/index.js";
|
||||
import { getAllSnippetsWithoutRace } from "../autocomplete/snippets/index.js";
|
||||
import { AutocompleteCodeSnippet } from "../autocomplete/snippets/types.js";
|
||||
@@ -415,6 +416,7 @@ export class NextEditProvider {
|
||||
filePath: helper.filepath,
|
||||
diffType: DiffFormatType.Unified,
|
||||
contextLines: 3,
|
||||
workspaceDir: workspaceDirs[0], // Use first workspace directory
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -468,33 +470,53 @@ export class NextEditProvider {
|
||||
}
|
||||
|
||||
// Extract completion using model-specific logic.
|
||||
const nextCompletion = this.modelProvider.extractCompletion(msg.content);
|
||||
let nextCompletion = this.modelProvider.extractCompletion(msg.content);
|
||||
|
||||
// Postprocess the completion (same as autocomplete).
|
||||
const postprocessed = postprocessCompletion({
|
||||
completion: nextCompletion,
|
||||
llm,
|
||||
prefix: helper.prunedPrefix,
|
||||
suffix: helper.prunedSuffix,
|
||||
});
|
||||
|
||||
// Return early if postprocessing filtered out the completion.
|
||||
if (!postprocessed) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
nextCompletion = postprocessed;
|
||||
|
||||
let outcome: NextEditOutcome | undefined;
|
||||
|
||||
// Handle based on diff type.
|
||||
const profileType =
|
||||
this.configHandler.currentProfile?.profileDescription.profileType;
|
||||
|
||||
if (opts?.usingFullFileDiff === false || !opts?.usingFullFileDiff) {
|
||||
outcome = await this.modelProvider.handlePartialFileDiff(
|
||||
outcome = await this.modelProvider.handlePartialFileDiff({
|
||||
helper,
|
||||
editableRegionStartLine,
|
||||
editableRegionEndLine,
|
||||
startTime,
|
||||
llm,
|
||||
nextCompletion,
|
||||
this.promptMetadata!,
|
||||
this.ide,
|
||||
);
|
||||
promptMetadata: this.promptMetadata!,
|
||||
ide: this.ide,
|
||||
profileType,
|
||||
});
|
||||
} else {
|
||||
outcome = await this.modelProvider.handleFullFileDiff(
|
||||
outcome = await this.modelProvider.handleFullFileDiff({
|
||||
helper,
|
||||
editableRegionStartLine,
|
||||
editableRegionEndLine,
|
||||
startTime,
|
||||
llm,
|
||||
nextCompletion,
|
||||
this.promptMetadata!,
|
||||
this.ide,
|
||||
);
|
||||
promptMetadata: this.promptMetadata!,
|
||||
ide: this.ide,
|
||||
profileType,
|
||||
});
|
||||
}
|
||||
|
||||
if (outcome) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPatch } from "diff";
|
||||
import { getUriPathBasename } from "../../util/uri";
|
||||
|
||||
export enum DiffFormatType {
|
||||
Unified = "unified",
|
||||
@@ -18,6 +19,7 @@ export interface CreateDiffArgs {
|
||||
filePath: string;
|
||||
diffType: DiffFormatType;
|
||||
contextLines: number;
|
||||
workspaceDir?: string;
|
||||
}
|
||||
|
||||
export const createDiff = ({
|
||||
@@ -26,6 +28,7 @@ export const createDiff = ({
|
||||
filePath,
|
||||
diffType,
|
||||
contextLines,
|
||||
workspaceDir,
|
||||
}: CreateDiffArgs) => {
|
||||
switch (diffType) {
|
||||
case DiffFormatType.Unified:
|
||||
@@ -34,6 +37,7 @@ export const createDiff = ({
|
||||
afterContent,
|
||||
filePath,
|
||||
contextLines,
|
||||
workspaceDir,
|
||||
);
|
||||
case DiffFormatType.TokenLineDiff:
|
||||
return createTokenLineDiff(beforeContent, afterContent, filePath);
|
||||
@@ -46,6 +50,7 @@ const createUnifiedDiff = (
|
||||
afterContent: string,
|
||||
filePath: string,
|
||||
contextLines: number,
|
||||
workspaceDir?: string,
|
||||
) => {
|
||||
const normalizedBefore = beforeContent.endsWith("\n")
|
||||
? beforeContent
|
||||
@@ -54,12 +59,21 @@ const createUnifiedDiff = (
|
||||
? afterContent
|
||||
: afterContent + "\n";
|
||||
|
||||
// Use relative path if workspace directory is provided
|
||||
let displayPath = filePath;
|
||||
if (workspaceDir && filePath.startsWith(workspaceDir)) {
|
||||
displayPath = filePath.slice(workspaceDir.length).replace(/^[\/]/, "");
|
||||
} else if (workspaceDir) {
|
||||
// Fallback to just the basename if we can't determine relative path
|
||||
displayPath = getUriPathBasename(filePath);
|
||||
}
|
||||
|
||||
const patch = createPatch(
|
||||
filePath,
|
||||
displayPath,
|
||||
normalizedBefore,
|
||||
normalizedAfter,
|
||||
"before",
|
||||
"after",
|
||||
undefined,
|
||||
undefined,
|
||||
{ context: contextLines },
|
||||
);
|
||||
|
||||
|
||||
@@ -127,6 +127,72 @@ describe("diffFormatting", () => {
|
||||
|
||||
expect(result).toContain("@@ -4,5 +4,5 @@");
|
||||
});
|
||||
|
||||
it("should use relative path when workspaceDir is provided", () => {
|
||||
const args: CreateDiffArgs = {
|
||||
beforeContent,
|
||||
afterContent,
|
||||
filePath: "file:///workspace/project/src/test.js",
|
||||
diffType: DiffFormatType.Unified,
|
||||
contextLines: 3,
|
||||
workspaceDir: "file:///workspace/project",
|
||||
};
|
||||
|
||||
const result = createDiff(args);
|
||||
|
||||
expect(result).toContain("--- src/test.js");
|
||||
expect(result).toContain("+++ src/test.js");
|
||||
expect(result).not.toContain("file://");
|
||||
expect(result).not.toContain("/workspace/project");
|
||||
});
|
||||
|
||||
it("should handle workspaceDir with trailing slash", () => {
|
||||
const args: CreateDiffArgs = {
|
||||
beforeContent,
|
||||
afterContent,
|
||||
filePath: "file:///workspace/project/src/test.js",
|
||||
diffType: DiffFormatType.Unified,
|
||||
contextLines: 3,
|
||||
workspaceDir: "file:///workspace/project/",
|
||||
};
|
||||
|
||||
const result = createDiff(args);
|
||||
|
||||
expect(result).toContain("--- src/test.js");
|
||||
expect(result).toContain("+++ src/test.js");
|
||||
});
|
||||
|
||||
it("should fallback to basename when path not in workspace", () => {
|
||||
const args: CreateDiffArgs = {
|
||||
beforeContent,
|
||||
afterContent,
|
||||
filePath: "file:///other/location/test.js",
|
||||
diffType: DiffFormatType.Unified,
|
||||
contextLines: 3,
|
||||
workspaceDir: "file:///workspace/project",
|
||||
};
|
||||
|
||||
const result = createDiff(args);
|
||||
|
||||
expect(result).toContain("--- test.js");
|
||||
expect(result).toContain("+++ test.js");
|
||||
});
|
||||
|
||||
it("should use full path when no workspaceDir provided", () => {
|
||||
const fullPath = "file:///workspace/project/src/test.js";
|
||||
const args: CreateDiffArgs = {
|
||||
beforeContent,
|
||||
afterContent,
|
||||
filePath: fullPath,
|
||||
diffType: DiffFormatType.Unified,
|
||||
contextLines: 3,
|
||||
};
|
||||
|
||||
const result = createDiff(args);
|
||||
|
||||
expect(result).toContain(`--- ${fullPath}`);
|
||||
expect(result).toContain(`+++ ${fullPath}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe("createBeforeAfterDiff", () => {
|
||||
|
||||
@@ -140,6 +140,7 @@ export const processNextEditData = async ({
|
||||
filePath: filePath,
|
||||
diffType: DiffFormatType.Unified,
|
||||
contextLines: 25, // storing many context lines for downstream trimming
|
||||
workspaceDir: workspaceDir,
|
||||
}),
|
||||
fileUri: filePath,
|
||||
workspaceUri: workspaceDir,
|
||||
|
||||
@@ -14,16 +14,6 @@ export const processSmallEdit = async (
|
||||
getDefsFromLspFunction: GetLspDefinitionsFunction,
|
||||
ide: IDE,
|
||||
) => {
|
||||
NextEditProvider.getInstance().addDiffToContext(
|
||||
createDiff({
|
||||
beforeContent: beforeAfterdiff.beforeContent,
|
||||
afterContent: beforeAfterdiff.afterContent,
|
||||
filePath: beforeAfterdiff.filePath,
|
||||
diffType: DiffFormatType.Unified,
|
||||
contextLines: 5, // NOTE: This can change depending on experiments!
|
||||
}),
|
||||
);
|
||||
|
||||
// Get the current context data from the most recent message
|
||||
const currentData = (EditAggregator.getInstance() as any)
|
||||
.latestContextData || {
|
||||
@@ -33,6 +23,17 @@ export const processSmallEdit = async (
|
||||
recentlyVisitedRanges: [],
|
||||
};
|
||||
|
||||
NextEditProvider.getInstance().addDiffToContext(
|
||||
createDiff({
|
||||
beforeContent: beforeAfterdiff.beforeContent,
|
||||
afterContent: beforeAfterdiff.afterContent,
|
||||
filePath: beforeAfterdiff.filePath,
|
||||
diffType: DiffFormatType.Unified,
|
||||
contextLines: 3, // NOTE: This can change depending on experiments!
|
||||
workspaceDir: currentData.workspaceDir,
|
||||
}),
|
||||
);
|
||||
|
||||
void processNextEditData({
|
||||
filePath: beforeAfterdiff.filePath,
|
||||
beforeContent: beforeAfterdiff.beforeContent,
|
||||
|
||||
@@ -47,16 +47,28 @@ export abstract class BaseNextEditModelProvider {
|
||||
};
|
||||
|
||||
// Methods that can be used as default fallback.
|
||||
public async handlePartialFileDiff(
|
||||
helper: HelperVars,
|
||||
editableRegionStartLine: number,
|
||||
editableRegionEndLine: number,
|
||||
startTime: number,
|
||||
llm: ILLM,
|
||||
nextCompletion: string,
|
||||
promptMetadata: PromptMetadata,
|
||||
ide: IDE,
|
||||
): Promise<NextEditOutcome> {
|
||||
public async handlePartialFileDiff(params: {
|
||||
helper: HelperVars;
|
||||
editableRegionStartLine: number;
|
||||
editableRegionEndLine: number;
|
||||
startTime: number;
|
||||
llm: ILLM;
|
||||
nextCompletion: string;
|
||||
promptMetadata: PromptMetadata;
|
||||
ide: IDE;
|
||||
profileType?: "local" | "platform" | "control-plane";
|
||||
}): Promise<NextEditOutcome> {
|
||||
const {
|
||||
helper,
|
||||
editableRegionStartLine,
|
||||
editableRegionEndLine,
|
||||
startTime,
|
||||
llm,
|
||||
nextCompletion,
|
||||
promptMetadata,
|
||||
ide,
|
||||
profileType,
|
||||
} = params;
|
||||
const oldEditRangeSlice = helper.fileContents
|
||||
.split("\n")
|
||||
.slice(editableRegionStartLine, editableRegionEndLine + 1)
|
||||
@@ -83,21 +95,34 @@ export abstract class BaseNextEditModelProvider {
|
||||
originalEditableRange: oldEditRangeSlice,
|
||||
diffLines: [],
|
||||
ide,
|
||||
profileType,
|
||||
});
|
||||
|
||||
return outcome;
|
||||
}
|
||||
|
||||
public async handleFullFileDiff(
|
||||
helper: HelperVars,
|
||||
editableRegionStartLine: number,
|
||||
editableRegionEndLine: number,
|
||||
startTime: number,
|
||||
llm: ILLM,
|
||||
nextCompletion: string,
|
||||
promptMetadata: PromptMetadata,
|
||||
ide: IDE,
|
||||
): Promise<NextEditOutcome | undefined> {
|
||||
public async handleFullFileDiff(params: {
|
||||
helper: HelperVars;
|
||||
editableRegionStartLine: number;
|
||||
editableRegionEndLine: number;
|
||||
startTime: number;
|
||||
llm: ILLM;
|
||||
nextCompletion: string;
|
||||
promptMetadata: PromptMetadata;
|
||||
ide: IDE;
|
||||
profileType?: "local" | "platform" | "control-plane";
|
||||
}): Promise<NextEditOutcome | undefined> {
|
||||
const {
|
||||
helper,
|
||||
editableRegionStartLine,
|
||||
editableRegionEndLine,
|
||||
startTime,
|
||||
llm,
|
||||
nextCompletion,
|
||||
promptMetadata,
|
||||
ide,
|
||||
profileType,
|
||||
} = params;
|
||||
const fileSlice = helper.fileLines
|
||||
.slice(editableRegionStartLine, editableRegionEndLine + 1)
|
||||
.join("\n");
|
||||
@@ -111,7 +136,7 @@ export abstract class BaseNextEditModelProvider {
|
||||
const currentLine = helper.pos.line;
|
||||
const prefetchQueue = PrefetchQueue.getInstance();
|
||||
|
||||
const cursorLocalDiffGroup = await this.processDiffGroups(
|
||||
const cursorLocalDiffGroup = await this.processDiffGroups({
|
||||
diffGroups,
|
||||
currentLine,
|
||||
helper,
|
||||
@@ -120,19 +145,21 @@ export abstract class BaseNextEditModelProvider {
|
||||
prefetchQueue,
|
||||
promptMetadata,
|
||||
ide,
|
||||
);
|
||||
profileType,
|
||||
});
|
||||
|
||||
if (cursorLocalDiffGroup) {
|
||||
return await this.createOutcomeFromDiffGroup(
|
||||
cursorLocalDiffGroup,
|
||||
return await this.createOutcomeFromDiffGroup({
|
||||
diffGroup: cursorLocalDiffGroup,
|
||||
helper,
|
||||
startTime,
|
||||
llm,
|
||||
helper.input.completionId,
|
||||
true,
|
||||
completionId: helper.input.completionId,
|
||||
isCurrentCursorGroup: true,
|
||||
promptMetadata,
|
||||
ide,
|
||||
);
|
||||
profileType,
|
||||
});
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@@ -141,23 +168,35 @@ export abstract class BaseNextEditModelProvider {
|
||||
/**
|
||||
* Process diff groups and find the one containing the cursor.
|
||||
*/
|
||||
private async processDiffGroups(
|
||||
diffGroups: DiffGroup[],
|
||||
currentLine: number,
|
||||
helper: HelperVars,
|
||||
startTime: number,
|
||||
llm: ILLM,
|
||||
prefetchQueue: PrefetchQueue,
|
||||
promptMetadata: PromptMetadata,
|
||||
ide: IDE,
|
||||
): Promise<DiffGroup | undefined> {
|
||||
private async processDiffGroups(params: {
|
||||
diffGroups: DiffGroup[];
|
||||
currentLine: number;
|
||||
helper: HelperVars;
|
||||
startTime: number;
|
||||
llm: ILLM;
|
||||
prefetchQueue: PrefetchQueue;
|
||||
promptMetadata: PromptMetadata;
|
||||
ide: IDE;
|
||||
profileType?: "local" | "platform" | "control-plane";
|
||||
}): Promise<DiffGroup | undefined> {
|
||||
const {
|
||||
diffGroups,
|
||||
currentLine,
|
||||
helper,
|
||||
startTime,
|
||||
llm,
|
||||
prefetchQueue,
|
||||
promptMetadata,
|
||||
ide,
|
||||
profileType,
|
||||
} = params;
|
||||
let cursorGroup: DiffGroup | undefined;
|
||||
|
||||
for (const group of diffGroups) {
|
||||
if (currentLine >= group.startLine && currentLine <= group.endLine) {
|
||||
cursorGroup = group;
|
||||
} else {
|
||||
await this.addDiffGroupToPrefetchQueue(
|
||||
await this.addDiffGroupToPrefetchQueue({
|
||||
group,
|
||||
helper,
|
||||
startTime,
|
||||
@@ -165,22 +204,34 @@ export abstract class BaseNextEditModelProvider {
|
||||
prefetchQueue,
|
||||
promptMetadata,
|
||||
ide,
|
||||
);
|
||||
profileType,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return cursorGroup;
|
||||
}
|
||||
|
||||
private async addDiffGroupToPrefetchQueue(
|
||||
group: DiffGroup,
|
||||
helper: HelperVars,
|
||||
startTime: number,
|
||||
llm: ILLM,
|
||||
prefetchQueue: PrefetchQueue,
|
||||
promptMetadata: PromptMetadata,
|
||||
ide: IDE,
|
||||
): Promise<void> {
|
||||
private async addDiffGroupToPrefetchQueue(params: {
|
||||
group: DiffGroup;
|
||||
helper: HelperVars;
|
||||
startTime: number;
|
||||
llm: ILLM;
|
||||
prefetchQueue: PrefetchQueue;
|
||||
promptMetadata: PromptMetadata;
|
||||
ide: IDE;
|
||||
profileType?: "local" | "platform" | "control-plane";
|
||||
}): Promise<void> {
|
||||
const {
|
||||
group,
|
||||
helper,
|
||||
startTime,
|
||||
llm,
|
||||
prefetchQueue,
|
||||
promptMetadata,
|
||||
ide,
|
||||
profileType,
|
||||
} = params;
|
||||
// Extract lines that are not old.
|
||||
const groupContent = group.lines
|
||||
.filter((l) => l.type !== "old")
|
||||
@@ -223,6 +274,7 @@ export abstract class BaseNextEditModelProvider {
|
||||
completionId: uuidv4(), // Generate a new ID for this prefetched item.
|
||||
diffLines: group.lines,
|
||||
ide,
|
||||
profileType,
|
||||
});
|
||||
|
||||
prefetchQueue.enqueueProcessed({
|
||||
@@ -231,16 +283,28 @@ export abstract class BaseNextEditModelProvider {
|
||||
});
|
||||
}
|
||||
|
||||
private async createOutcomeFromDiffGroup(
|
||||
diffGroup: DiffGroup,
|
||||
helper: HelperVars,
|
||||
startTime: number,
|
||||
llm: ILLM,
|
||||
completionId: string,
|
||||
isCurrentCursorGroup: boolean,
|
||||
promptMetadata: PromptMetadata,
|
||||
ide: IDE,
|
||||
): Promise<NextEditOutcome> {
|
||||
private async createOutcomeFromDiffGroup(params: {
|
||||
diffGroup: DiffGroup;
|
||||
helper: HelperVars;
|
||||
startTime: number;
|
||||
llm: ILLM;
|
||||
completionId: string;
|
||||
isCurrentCursorGroup: boolean;
|
||||
promptMetadata: PromptMetadata;
|
||||
ide: IDE;
|
||||
profileType?: "local" | "platform" | "control-plane";
|
||||
}): Promise<NextEditOutcome> {
|
||||
const {
|
||||
diffGroup,
|
||||
helper,
|
||||
startTime,
|
||||
llm,
|
||||
completionId,
|
||||
isCurrentCursorGroup,
|
||||
promptMetadata,
|
||||
ide,
|
||||
profileType,
|
||||
} = params;
|
||||
const groupContent = diffGroup.lines
|
||||
.filter((l) => l.type !== "old")
|
||||
.map((l) => l.line)
|
||||
@@ -278,6 +342,7 @@ export abstract class BaseNextEditModelProvider {
|
||||
completionId,
|
||||
diffLines: diffGroup.lines,
|
||||
ide,
|
||||
profileType,
|
||||
});
|
||||
|
||||
return outcomeNext;
|
||||
@@ -299,6 +364,7 @@ export abstract class BaseNextEditModelProvider {
|
||||
completionId?: string;
|
||||
diffLines: DiffLine[];
|
||||
ide: IDE;
|
||||
profileType?: "local" | "platform" | "control-plane";
|
||||
}): Promise<NextEditOutcome> {
|
||||
return {
|
||||
elapsed: Date.now() - outcomeCtx.startTime,
|
||||
@@ -325,6 +391,7 @@ export abstract class BaseNextEditModelProvider {
|
||||
editableRegionStartLine: outcomeCtx.editableRegionStartLine,
|
||||
editableRegionEndLine: outcomeCtx.editableRegionEndLine,
|
||||
diffLines: outcomeCtx.diffLines,
|
||||
profileType: outcomeCtx.profileType,
|
||||
...outcomeCtx.helper.options,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ export interface NextEditOutcome extends TabAutocompleteOptions {
|
||||
editableRegionStartLine: number;
|
||||
editableRegionEndLine: number;
|
||||
diffLines: DiffLine[];
|
||||
profileType?: "local" | "platform" | "control-plane";
|
||||
}
|
||||
|
||||
export interface PromptMetadata {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "continue",
|
||||
"icon": "media/icon.png",
|
||||
"author": "Continue Dev, Inc",
|
||||
"version": "1.3.15",
|
||||
"version": "1.2.8",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/continuedev/continue"
|
||||
|
||||
@@ -135,7 +135,7 @@ export class GhostTextAcceptanceTracker {
|
||||
);
|
||||
|
||||
if (wasGhostTextAccepted) {
|
||||
console.log(
|
||||
console.debug(
|
||||
"GhostTextAcceptanceTracker: ghost text was accepted, preserving chain",
|
||||
);
|
||||
return true;
|
||||
|
||||
@@ -3,9 +3,6 @@ import { AutocompleteCodeSnippet } from "core/autocomplete/snippets/types";
|
||||
import { GetLspDefinitionsFunction } from "core/autocomplete/types";
|
||||
import { ConfigHandler } from "core/config/ConfigHandler";
|
||||
import { RecentlyEditedRange } from "core/nextEdit/types";
|
||||
import { getContinueGlobalPath, isFileWithinFolder } from "core/util/paths";
|
||||
import fs from "fs";
|
||||
import { resolve } from "path";
|
||||
import * as vscode from "vscode";
|
||||
import { ContinueCompletionProvider } from "../autocomplete/completionProvider";
|
||||
|
||||
@@ -21,23 +18,6 @@ export const getBeforeCursorPos = (range: Range, activePos: Position) => {
|
||||
}
|
||||
};
|
||||
|
||||
const isEditLoggingAllowed = async (editedFileURI: string) => {
|
||||
const globalContinuePath = getContinueGlobalPath();
|
||||
const editLogDirsPath = resolve(globalContinuePath, ".editlogdirs");
|
||||
|
||||
try {
|
||||
const fileContent = await fs.promises.readFile(editLogDirsPath, "utf-8");
|
||||
const stringItems = fileContent
|
||||
.split("\n")
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line.length > 0);
|
||||
|
||||
return stringItems.some((dir) => isFileWithinFolder(editedFileURI, dir));
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const getWorkspaceDirUri = async (event: vscode.TextDocumentChangeEvent) => {
|
||||
const workspaceFolder = vscode.workspace.getWorkspaceFolder(
|
||||
event.document.uri,
|
||||
@@ -68,7 +48,6 @@ export const handleTextDocumentChange = async (
|
||||
// Ensure that logging will only happen in the open-source continue repo
|
||||
const workspaceDirUri = await getWorkspaceDirUri(event);
|
||||
if (!workspaceDirUri) return;
|
||||
if (!(await isEditLoggingAllowed(event.document.uri.toString()))) return;
|
||||
|
||||
const activeCursorPos = editor.selection.active;
|
||||
const editActions: RangeInFileWithNextEditInfo[] = changes.map((change) => ({
|
||||
|
||||
Reference in New Issue
Block a user