From 5c99f011e86bbf611ab8677a01e471225c96da19 Mon Sep 17 00:00:00 2001 From: Harvmaster Date: Sun, 4 Oct 2026 00:15:11 +0000 Subject: [PATCH] Next-edit: treat empty model output as no-edit llama-server leaves special tokens out of content, so the NO_EDIT token arrives as an empty string. The daemon treated that as a rewrite of the region to nothing (Tab would have deleted the region). shared/nextedit.ts parseNextEditOutput() is now used by the daemon and the eval. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01J39imRDT8L7xYbWzsVWd8A --- daemon/src/main.ts | 6 +++--- shared/nextedit.ts | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/daemon/src/main.ts b/daemon/src/main.ts index b7ec58d..b916e2f 100644 --- a/daemon/src/main.ts +++ b/daemon/src/main.ts @@ -31,7 +31,7 @@ import { symbolLang } from '../../shared/symbol-lang.ts' import { SymbolService, mightNeedThis } from './symbols.ts' import { EditTracker } from './edits.ts' import { locateFile, modeFromModel, parseFimPrompt } from './openai-shim.ts' -import { NEXT_EDIT_TOKENS } from '../../shared/nextedit.ts' +import { NEXT_EDIT_TOKENS, parseNextEditOutput } from '../../shared/nextedit.ts' const { values: args } = parseArgs({ options: { config: { type: 'string', default: 'acd.config.json' } } }) const config = loadConfig(args.config!) @@ -272,8 +272,8 @@ async function handleNextEdit(body: NextEditRequest, res: http.ServerResponse, c const oldText = lines.slice(startLine, endLine).join('\n') + (endLine < lines.length ? '\n' : '') const raw = result.text - const newText = raw.startsWith(NEXT_EDIT_TOKENS.noEdit) ? null : raw - const noEdit = newText === null || newText === oldText || result.stoppedBy === 'limit' + const newText = parseNextEditOutput(raw, oldText) + const noEdit = newText === null || result.stoppedBy === 'limit' const response = { requestId: body.requestId, noEdit, startLine, endLine, oldText, newText: noEdit ? null : newText, recentEdits, errors: errors ?? null, model: state.model, diff --git a/shared/nextedit.ts b/shared/nextedit.ts index b0a32b7..9af1f97 100644 --- a/shared/nextedit.ts +++ b/shared/nextedit.ts @@ -154,3 +154,12 @@ export function buildNextEditPrompt(input: NextEditInput, encode: Encode, ids: N export function nextEditTarget(newRegion: string | null, encode: Encode, ids: NextEditTokenIds): number[] { return newRegion === null ? [ids.noEdit, ids.outputEnd] : [...encode(newRegion), ids.outputEnd] } + +/** + * Model output → rewritten region, or null for "no edit". llama-server leaves special tokens out of `content`, so the + * NO_EDIT token usually arrives as an empty string; never treat empty output as "replace the region with nothing". + */ +export function parseNextEditOutput(raw: string, oldText: string): string | null { + if (raw.startsWith(NEXT_EDIT_TOKENS.noEdit) || raw.trim() === '' || raw === oldText) return null + return raw +}