2 Commits
Author SHA1 Message Date
HarvmasterandClaude Opus 5.5 9ccf108835 Extension: request the next edit right after accepting a suggestion (0.6.4)
ci / build (push) Canceled after 0s
Accepting a completion or a next-edit cancels the debounce timer and asks the daemon for
the follow-up immediately; next-edits chain. Setting localAutocomplete.nextEdit.afterAccept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J39imRDT8L7xYbWzsVWd8A
2026-10-04 01:11:39 +00:00
HarvmasterandClaude Opus 5.5 3dc916834f Daemon: a changed default model overrides the saved state (0.6.3)
ci / build (push) Canceled after 0s
In managed mode the extension switches models by rewriting the daemon config's
defaultModel and restarting it, but loadState() preferred the persisted model, so the
daemon came back on the old one every time. State now records the default it was saved
under; a different default wins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J39imRDT8L7xYbWzsVWd8A
2026-10-04 01:06:31 +00:00
4 changed files with 35 additions and 4 deletions
+12
View File
@@ -2,6 +2,18 @@
Extension versions are released as `vscode-v<version>` on the [Releases](https://git.harvmaster.com/Harvmaster/autocomplete-model/releases) page. Models are versioned by their name in [`models/manifest.json`](models/manifest.json). Extension versions are released as `vscode-v<version>` on the [Releases](https://git.harvmaster.com/Harvmaster/autocomplete-model/releases) page. Models are versioned by their name in [`models/manifest.json`](models/manifest.json).
## vscode 0.6.4
- **Accepting a suggestion asks for the next edit immediately** (setting `nextEdit.afterAccept`, on by default). After
Tab on a completion or a next-edit, the follow-up is requested right away instead of after the typing pause, so
accepted next-edits chain (rename → next use → …).
## vscode 0.6.3
- **Fix: model choice didn't stick in managed mode.** The daemon's saved state (last model used) overrode both the
model picked in the menu and a new default from a release, so it kept restarting on the old model (e.g.
`stage-c`). A changed default now wins; switching through the daemon API still persists as before.
## vscode 0.6.2 ## vscode 0.6.2
- **Next-edit is ~3–5× faster:** the next-edit server uses n-gram speculative decoding (the rewritten region is mostly - **Next-edit is ~3–5× faster:** the next-edit server uses n-gram speculative decoding (the rewritten region is mostly
+6 -3
View File
@@ -76,6 +76,8 @@ export interface RuntimeState {
enabled: boolean enabled: boolean
model: string model: string
mode: ContextMode mode: ContextMode
/** config.defaultModel when this state was saved: a changed default (editor model setting, new release) wins. */
defaultModel?: string
} }
export function loadConfig(configPath: string): DaemonConfig { export function loadConfig(configPath: string): DaemonConfig {
@@ -97,12 +99,13 @@ export function loadConfig(configPath: string): DaemonConfig {
} }
export function loadState(config: DaemonConfig): RuntimeState { export function loadState(config: DaemonConfig): RuntimeState {
const fallback: RuntimeState = { enabled: true, model: config.defaultModel, mode: config.models[config.defaultModel].defaultMode } const fallback: RuntimeState = { enabled: true, model: config.defaultModel, mode: config.models[config.defaultModel].defaultMode, defaultModel: config.defaultModel }
try { try {
const s = JSON.parse(fs.readFileSync(config.stateFile, 'utf8')) as Partial<RuntimeState> const s = JSON.parse(fs.readFileSync(config.stateFile, 'utf8')) as Partial<RuntimeState>
const model = s.model && config.models[s.model] ? s.model : fallback.model const keepModel = s.defaultModel === config.defaultModel && s.model && config.models[s.model]
const model = keepModel ? s.model! : fallback.model
const mode = s.mode && config.models[model].modes.includes(s.mode) ? s.mode : config.models[model].defaultMode const mode = s.mode && config.models[model].modes.includes(s.mode) ? s.mode : config.models[model].defaultMode
return { enabled: s.enabled ?? true, model, mode } return { enabled: s.enabled ?? true, model, mode, defaultModel: config.defaultModel }
} catch { } catch {
return fallback return fallback
} }
+6 -1
View File
@@ -3,7 +3,7 @@
"displayName": "Local Autocomplete", "displayName": "Local Autocomplete",
"description": "Inline code completion from a local fine-tuned model via the acd daemon", "description": "Inline code completion from a local fine-tuned model via the acd daemon",
"publisher": "harvmaster", "publisher": "harvmaster",
"version": "0.6.2", "version": "0.6.4",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"vscode": "^1.90.0" "vscode": "^1.90.0"
@@ -218,6 +218,11 @@
"default": 700, "default": 700,
"description": "Pause after typing before asking for a next-edit suggestion." "description": "Pause after typing before asking for a next-edit suggestion."
}, },
"localAutocomplete.nextEdit.afterAccept": {
"type": "boolean",
"default": true,
"description": "After you accept a completion or a next-edit suggestion, immediately ask for the next edit (without waiting for the typing pause). Accepted next-edits chain: a rename suggests the next use, and so on."
},
"localAutocomplete.triggerOnCursorMove": { "localAutocomplete.triggerOnCursorMove": {
"type": "boolean", "type": "boolean",
"default": false, "default": false,
+11
View File
@@ -259,6 +259,7 @@ const modelSupportsNextEdit = () => !!(daemonConfig && daemonConfig.models[daemo
// ---------- next-edit prediction (models trained for it, e.g. Stage E) // ---------- next-edit prediction (models trained for it, e.g. Stage E)
const nextEdit = new NextEditController(s => { const nextEdit = new NextEditController(s => {
api('POST', '/v1/feedback', { event: 'next-edit-accepted', lines: s.newText.split('\n').length }).catch(() => {}) api('POST', '/v1/feedback', { event: 'next-edit-accepted', lines: s.newText.split('\n').length }).catch(() => {})
nextEditAfterAccept('accepted-next-edit')
}) })
let nextEditTimer: NodeJS.Timeout | null = null let nextEditTimer: NodeJS.Timeout | null = null
let nextEditAbort: AbortController | null = null let nextEditAbort: AbortController | null = null
@@ -281,6 +282,15 @@ async function requestNextEdit(editor: vscode.TextEditor, reason: string) {
} }
} }
/** Accepting a suggestion (next-edit or completion) asks for the follow-up right away instead of after the typing pause. */
function nextEditAfterAccept(reason: string) {
const editor = vscode.window.activeTextEditor
if (!editor || !modelSupportsNextEdit() || !settings().get<boolean>('nextEdit.afterAccept', true)) return
if (nextEditTimer) clearTimeout(nextEditTimer)
// Next tick: the accepted text and the cursor move have been applied by then.
nextEditTimer = setTimeout(() => void requestNextEdit(editor, reason), 0)
}
function scheduleNextEdit(editor: vscode.TextEditor, reason: string, delay: number) { function scheduleNextEdit(editor: vscode.TextEditor, reason: string, delay: number) {
if (nextEditTimer) clearTimeout(nextEditTimer) if (nextEditTimer) clearTimeout(nextEditTimer)
nextEditTimer = setTimeout(() => void requestNextEdit(editor, reason), delay) nextEditTimer = setTimeout(() => void requestNextEdit(editor, reason), delay)
@@ -535,6 +545,7 @@ export async function activate(ctx: vscode.ExtensionContext) {
vscode.commands.registerCommand('localAutocomplete.showLog', () => log.show()), vscode.commands.registerCommand('localAutocomplete.showLog', () => log.show()),
vscode.commands.registerCommand('localAutocomplete.accepted', (requestId: string, text: string) => { vscode.commands.registerCommand('localAutocomplete.accepted', (requestId: string, text: string) => {
api('POST', '/v1/feedback', { requestId, event: 'accepted', chars: text.length }).catch(() => {}) api('POST', '/v1/feedback', { requestId, event: 'accepted', chars: text.length }).catch(() => {})
nextEditAfterAccept('accepted-completion')
}), }),
vscode.workspace.onDidChangeConfiguration(e => { vscode.workspace.onDidChangeConfiguration(e => {
if (!e.affectsConfiguration('localAutocomplete')) return if (!e.affectsConfiguration('localAutocomplete')) return