Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
4d1b2be
feat: don't format when model is not mercury
jpoly1219 Aug 21, 2025
226a1d2
chore: bump
jpoly1219 Aug 21, 2025
5fe6ac9
fix: remove mercury-coder-nextedit
jpoly1219 Aug 21, 2025
0e6f6b4
refactor: remove refs to mercury-coder-nextedit
jpoly1219 Aug 21, 2025
70814ec
feat: add util function for converting model name to enum
jpoly1219 Aug 21, 2025
302e97a
refactor: add new types
jpoly1219 Aug 22, 2025
89e8d8e
refactor: create an abstract base class for providers
jpoly1219 Aug 22, 2025
b19a251
refactor: add child provider for instinct
jpoly1219 Aug 22, 2025
5d13b56
refactor: add provider for mercury coder
jpoly1219 Aug 22, 2025
8291dd1
refactor: provider factory
jpoly1219 Aug 22, 2025
37aa08e
refactor: use factory to create model providers based on helper.model…
jpoly1219 Aug 22, 2025
df2ef1c
refactor: clean up redundant logic to be more provider-friendly
jpoly1219 Aug 22, 2025
8787af5
add buildPromptMetadata as an abstract method
jpoly1219 Aug 22, 2025
15c8b9c
refactor: use handlebars and provider-specific template renderers
jpoly1219 Aug 22, 2025
361dc94
refactor: use this.modelProvider instead of prompt engine
jpoly1219 Aug 22, 2025
d1ec7cf
refactor: remove redundant helper
jpoly1219 Aug 22, 2025
25dbb22
fix: update vitest after refactor
jpoly1219 Aug 22, 2025
8177095
feat: add test for convertNextEditModelNameToEnum
jpoly1219 Aug 22, 2025
2c2f79e
Merge branch 'main' of github.com:continuedev/continue into jacob/con…
jpoly1219 Aug 22, 2025
f5acecd
fix: add isSecurityConcern imports
jpoly1219 Aug 22, 2025
8c443ed
Merge branch 'main' of github.com:continuedev/continue into jacob/con…
jpoly1219 Aug 22, 2025
11e5aff
feat: add functions to return next edit menu items and update config
jpoly1219 Aug 22, 2025
4a57b4d
fix: get rid of callbacks
jpoly1219 Aug 22, 2025
f6ff975
feat: render next edit menu items
jpoly1219 Aug 22, 2025
c9d8d5e
fix: get rid of redundant completion request
jpoly1219 Aug 22, 2025
abdf02e
feat: update next edit status on vscode workspace config update, refa…
jpoly1219 Aug 22, 2025
6a10ca7
feat: add continue.enableNextEdit
jpoly1219 Aug 22, 2025
7e6e9c0
feat: add aborted field to check for false positives
jpoly1219 Aug 22, 2025
29e4521
fix: remove zetaDataset suffix
jpoly1219 Aug 22, 2025
2deec49
feat: make sure that we are tracking completions
jpoly1219 Aug 22, 2025
b354154
feat: log aborts and move id generation to the top
jpoly1219 Aug 22, 2025
b09d61a
feat: all requests are tracked. when request is aborted, log as abort…
jpoly1219 Aug 22, 2025
7d07e2f
feat: add aborted to schema
jpoly1219 Aug 22, 2025
4ba4f7e
feat: add a toggleNextEditEnabled command
jpoly1219 Aug 22, 2025
00ac50d
feat: show (NE) in the status bar when next edit is enabled, add keymap
jpoly1219 Aug 22, 2025
ee67660
feat: add command definitions for toggleNextEditEnabled
jpoly1219 Aug 22, 2025
67ef460
refactor: handle validation in VsCodeExtension
jpoly1219 Aug 22, 2025
43741ed
feat: check if model does not support next edit
jpoly1219 Aug 22, 2025
cb6086b
feat: use better menu item labels
jpoly1219 Aug 22, 2025
d0d1b7e
Merge branch 'main' of github.com:continuedev/continue into jacob/con…
jpoly1219 Aug 22, 2025
73a328c
fix: casing
jpoly1219 Aug 23, 2025
bfa97cf
chore: bump
jpoly1219 Aug 23, 2025
7f457a3
Merge branch 'main' of github.com:continuedev/continue into jacob/con…
jpoly1219 Aug 23, 2025
181bd3a
feat: add a function to disable next edit
jpoly1219 Aug 23, 2025
d83e3df
feat: disable next edit before e2e tests
jpoly1219 Aug 23, 2025
c4481ce
chore: bump
jpoly1219 Aug 23, 2025
4f977c9
fix: add a small delay to wait for UI loading
jpoly1219 Aug 23, 2025
ae20609
fix: NE is shown for all statuses
jpoly1219 Aug 23, 2025
8874871
fix: wait for the NE to pop up
jpoly1219 Aug 23, 2025
860ff6b
fix: wait longer for disableNextEdit, clear potential next edit notif…
jpoly1219 Aug 23, 2025
48f30ee
fix: roll back clearAllNotifications
jpoly1219 Aug 23, 2025
c030382
fix: try disabling next edit before each
jpoly1219 Aug 23, 2025
3a47dbd
fix: revert
jpoly1219 Aug 23, 2025
d8f4231
feat: add sane defaults when no workspace settings are set
jpoly1219 Aug 23, 2025
a278533
fix: fall back to false
jpoly1219 Aug 23, 2025
18fdfde
Merge branch 'main' of github.com:continuedev/continue into jacob/con…
jpoly1219 Aug 24, 2025
efe78c0
fix: debugging
jpoly1219 Aug 24, 2025
0d69138
chore: change name
jpoly1219 Aug 24, 2025
b028769
fix: try waiting for text
jpoly1219 Aug 24, 2025
17eb579
debug: more debug logs
jpoly1219 Aug 24, 2025
16422a8
fix: clear notifs
jpoly1219 Aug 24, 2025
1370f4a
fix: suppress warning
jpoly1219 Aug 24, 2025
bf72c61
fix: string matching
jpoly1219 Aug 24, 2025
386e7ca
Merge branch 'main' into jacob/con-3584
jpoly1219 Aug 25, 2025
96c987b
fix: jump label overlapping with the inline tip label (#7399)
jpoly1219 Aug 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions core/autocomplete/CompletionProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,6 @@ export class CompletionProvider {
const multiline =
!helper.options.transform || shouldCompleteMultiline(helper);

const rawGeneration = await llm.complete(
prompt,
token,
completionOptions,
);

const completionStream =
this.completionStreamer.streamCompletionWithFilters(
token,
Expand Down
6 changes: 5 additions & 1 deletion core/config/loadLocalAssistants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ async function getDefinitionFilesInDir(
}

const overrideDefaultIgnores = ignore()
.add(DEFAULT_IGNORE_FILETYPES.filter((t) => t !== "config.yaml"))
.add(
DEFAULT_IGNORE_FILETYPES.filter(
(t) => t !== "config.yaml" && t !== "config.yml",
),
)
.add(DEFAULT_IGNORE_DIRS);

const uris = await walkDir(dir, ide, {
Expand Down
41 changes: 33 additions & 8 deletions core/config/loadLocalAssistants.vitest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ describe("ASSISTANTS getAllDotContinueDefinitionFiles with fileExtType option",
[".continue/assistants/assistant2.yml", "yaml content 2"],
[".continue/assistants/assistant3.md", "markdown content 1"],
[".continue/assistants/assistant4.txt", "txt content"],
[".continue/assistants/config.yaml", "txt content"],
[".continue/assistants/config.yml", "txt content"],
]);
});

Expand All @@ -38,9 +40,14 @@ describe("ASSISTANTS getAllDotContinueDefinitionFiles with fileExtType option",
options,
"assistants",
);
expect(result).toHaveLength(2);
expect(result).toHaveLength(4);
expect(result.map((f) => f.path.split("/").pop())).toEqual(
expect.arrayContaining(["assistant1.yaml", "assistant2.yml"]),
expect.arrayContaining([
"assistant1.yaml",
"assistant2.yml",
"config.yaml",
"config.yml",
]),
);
expect(result.map((f) => f.path.split("/").pop())).not.toContain(
"assistant3.md",
Expand Down Expand Up @@ -69,6 +76,12 @@ describe("ASSISTANTS getAllDotContinueDefinitionFiles with fileExtType option",
expect(result.map((f) => f.path.split("/").pop())).not.toContain(
"assistant2.yml",
);
expect(result.map((f) => f.path.split("/").pop())).not.toContain(
"config.yml",
);
expect(result.map((f) => f.path.split("/").pop())).not.toContain(
"config.yaml",
);
});

it("should return all supported files when fileExtType is not specified", async () => {
Expand All @@ -83,11 +96,13 @@ describe("ASSISTANTS getAllDotContinueDefinitionFiles with fileExtType option",
options,
"assistants",
);
expect(result).toHaveLength(3);
expect(result).toHaveLength(5);
expect(result.map((f) => f.path.split("/").pop())).toEqual(
expect.arrayContaining([
"assistant1.yaml",
"assistant2.yml",
"config.yml",
"config.yaml",
"assistant3.md",
]),
);
Expand Down Expand Up @@ -124,9 +139,14 @@ describe("ASSISTANTS getAllDotContinueDefinitionFiles with fileExtType option",
workspaceOnOptions,
"assistants",
);
expect(workspaceResult).toHaveLength(2);
expect(workspaceResult).toHaveLength(4);
expect(workspaceResult.map((f) => f.path.split("/").pop())).toEqual(
expect.arrayContaining(["assistant1.yaml", "assistant2.yml"]),
expect.arrayContaining([
"assistant1.yaml",
"assistant2.yml",
"config.yaml",
"config.yml",
]),
);
});

Expand Down Expand Up @@ -187,7 +207,7 @@ describe("ASSISTANTS getAllDotContinueDefinitionFiles with fileExtType option",
options,
"assistants",
);
expect(result).toHaveLength(2);
expect(result).toHaveLength(4);
const yamlFile = result.find((f) => f.path.includes("assistant1.yaml"));
expect(yamlFile?.content).toBe("yaml content 1");
});
Expand All @@ -212,9 +232,14 @@ describe("ASSISTANTS getAllDotContinueDefinitionFiles with fileExtType option",
"assistants",
);
// Should only get lowercase extensions (current implementation)
expect(yamlResult).toHaveLength(2);
expect(yamlResult).toHaveLength(4);
expect(yamlResult.map((f) => f.path.split("/").pop())).toEqual(
expect.arrayContaining(["assistant1.yaml", "assistant2.yml"]),
expect.arrayContaining([
"assistant1.yaml",
"assistant2.yml",
"config.yaml",
"config.yml",
]),
);
expect(yamlResult.map((f) => f.path.split("/").pop())).not.toContain(
"assistant5.YAML",
Expand Down
111 changes: 110 additions & 1 deletion core/nextEdit/NextEditLoggingService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ export class NextEditLoggingService {
private _abortControllers = new Map<string, AbortController>();
private _logRejectionTimeouts = new Map<string, NodeJS.Timeout>();
private _outcomes = new Map<string, NextEditOutcome>();
// Track minimal data for completions that get aborted before we have full outcome.
private _pendingCompletions = new Map<
string,
{
startTime: number;
modelName?: string;
modelProvider?: string;
filepath?: string;
}
>();
_lastDisplayedCompletion: { id: string; displayedAt: number } | undefined =
undefined;

Expand All @@ -26,35 +36,71 @@ export class NextEditLoggingService {
public createAbortController(completionId: string): AbortController {
const abortController = new AbortController();
this._abortControllers.set(completionId, abortController);
this.trackPendingCompletion(completionId);
return abortController;
}

public deleteAbortController(completionId: string) {
this._abortControllers.delete(completionId);
this._pendingCompletions.delete(completionId);
}

// Keep track of a new completion request.
public trackPendingCompletion(completionId: string) {
this._pendingCompletions.set(completionId, {
startTime: Date.now(),
});
}

// Update pending completion info as it becomes available.
public updatePendingCompletion(
completionId: string,
data: {
modelName?: string;
modelProvider?: string;
filepath?: string;
},
) {
const pending = this._pendingCompletions.get(completionId);
if (pending) {
this._pendingCompletions.set(completionId, { ...pending, ...data });
} else {
// If we haven't tracked it yet, create new entry with provided data.
this._pendingCompletions.set(completionId, {
startTime: Date.now(),
...data,
});
}
}

public cancel() {
this._abortControllers.forEach((abortController, id) => {
this._abortControllers.forEach((abortController, completionId) => {
this.handleAbort(completionId);
abortController.abort();
});
this._abortControllers.clear();
}

public accept(completionId: string): NextEditOutcome | undefined {
this._pendingCompletions.delete(completionId);

if (this._logRejectionTimeouts.has(completionId)) {
clearTimeout(this._logRejectionTimeouts.get(completionId));
this._logRejectionTimeouts.delete(completionId);
}
if (this._outcomes.has(completionId)) {
const outcome = this._outcomes.get(completionId)!;
outcome.accepted = true;
outcome.aborted = false;
this.logNextEditOutcome(outcome);
this._outcomes.delete(completionId);
return outcome;
}
}

public reject(completionId: string): NextEditOutcome | undefined {
this._pendingCompletions.delete(completionId);

if (this._logRejectionTimeouts.has(completionId)) {
clearTimeout(this._logRejectionTimeouts.get(completionId));
this._logRejectionTimeouts.delete(completionId);
Expand All @@ -63,6 +109,7 @@ export class NextEditLoggingService {
if (this._outcomes.has(completionId)) {
const outcome = this._outcomes.get(completionId)!;
outcome.accepted = false;
outcome.aborted = false;
this.logNextEditOutcome(outcome);
this._outcomes.delete(completionId);
return outcome;
Expand All @@ -86,12 +133,19 @@ export class NextEditLoggingService {
}

public markDisplayed(completionId: string, outcome: NextEditOutcome) {
// Remove from pending since we now have full data.
this._pendingCompletions.delete(completionId);
outcome.aborted = false;

const logRejectionTimeout = setTimeout(() => {
// Wait 10 seconds, then assume it wasn't accepted
outcome.accepted = false;
outcome.aborted = false;
this.logNextEditOutcome(outcome);
this._logRejectionTimeouts.delete(completionId);
this._outcomes.delete(completionId);
}, COUNT_COMPLETION_REJECTED_AFTER);

this._outcomes.set(completionId, outcome);
this._logRejectionTimeouts.set(completionId, logRejectionTimeout);

Expand Down Expand Up @@ -124,7 +178,62 @@ export class NextEditLoggingService {
};
}

public handleAbort(completionId: string) {
// Clear any pending rejection timeout.
if (this._logRejectionTimeouts.has(completionId)) {
clearTimeout(this._logRejectionTimeouts.get(completionId));
this._logRejectionTimeouts.delete(completionId);
}

// If we have the full outcome, log it as aborted.
if (this._outcomes.has(completionId)) {
const outcome = this._outcomes.get(completionId)!;
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.
this._pendingCompletions.delete(completionId);
}

private logNextEditOutcome(outcome: NextEditOutcome) {
if (outcome.aborted === undefined) {
outcome.aborted = false;
}

void DataLogger.getInstance().logDevData({
name: "nextEditOutcome",
data: outcome,
Expand Down
11 changes: 11 additions & 0 deletions core/nextEdit/NextEditProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,11 @@ export class NextEditProvider {
input.completionId,
);
token = controller.signal;
} else {
// Token was provided externally, just track the completion.
this.loggingService.trackPendingCompletion(input.completionId);
}

const startTime = Date.now();
const options = await this._getAutocompleteOptions();

Expand All @@ -325,6 +329,13 @@ export class NextEditProvider {
return { token, startTime, helper: undefined };
}

// Update pending completion with model info.
this.loggingService.updatePendingCompletion(input.completionId, {
modelName: llm.model,
modelProvider: llm.providerName,
filepath: input.filepath,
});

// Check model capabilities
if (!modelSupportsNextEdit(llm.capabilities, llm.model, llm.title)) {
console.error(`${llm.model} is not capable of next edit.`);
Expand Down
2 changes: 1 addition & 1 deletion core/nextEdit/providers/BaseNextEditProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ export abstract class BaseNextEditProvider {
return {
elapsed: Date.now() - outcomeCtx.startTime,
modelProvider: outcomeCtx.llm.underlyingProviderName,
modelName: outcomeCtx.llm.model + ":zetaDataset",
modelName: outcomeCtx.llm.model,
completionOptions: null,
completionId:
outcomeCtx.completionId || outcomeCtx.helper.input.completionId,
Expand Down
1 change: 1 addition & 0 deletions core/nextEdit/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export interface NextEditOutcome extends TabAutocompleteOptions {
cursorPosition: { line: number; character: number };
finalCursorPosition: { line: number; character: number };
accepted?: boolean;
aborted?: boolean;
editableRegionStartLine: number;
editableRegionEndLine: number;
diffLines: DiffLine[];
Expand Down
Loading
Loading