Extension 0.6.0: next-edit, token healing, TS errors context, cursor-move, prewarm
ci / build (push) Canceled after 0s
ci / build (push) Canceled after 0s
- shared/nextedit.ts: next-edit prompt format (region rewrite or NO_EDIT, Qwen spare special tokens) - shared/diagnostics.ts: TS errors near the cursor as context; symbols format 2 adds namespace imports - shared/prompt.ts: token healing (cut the half-typed word, force it via grammar), errors header section - daemon: model profiles carry contextFormat/errors/members/nextEdit; /v1/next-edit with edit-burst tracking; /v1/prewarm; /v1/debug/last; token healing on by default - extension: next-edit decorations (Tab apply / Esc dismiss), suggest on cursor move, prewarm on focus, Show Last Prompt, update check against releases, diagnostics in the edit recorder - models/README: training-data attribution; release script profiles for stage-d/stage-e - .gitea/workflows/ci.yml: build + test, publish release on vscode-v* tags (needs a runner + RELEASE_TOKEN) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J39imRDT8L7xYbWzsVWd8A
This commit is contained in:
+25
-6
@@ -29,14 +29,14 @@ export function fimPrompt(order: FimOrder, prefix: number[], suffix: number[], i
|
||||
|
||||
/**
|
||||
* Qwen2.5-Coder repo-level header placed before the FIM prompt:
|
||||
* <repo_name>repo\n [<file_sep>dir/__symbols__.d.ts\n{context}\n] <file_sep>path\n
|
||||
* <repo_name>repo\n [<file_sep>dir/__symbols__.d.ts\n{context}\n] [<file_sep>dir/__errors__.txt\n{errors}\n] <file_sep>path\n
|
||||
*/
|
||||
export function repoHeader(repo: string, filePath: string, context: string | undefined, encode: Encode, ids: HeaderTokenIds): number[] {
|
||||
export function repoHeader(repo: string, filePath: string, context: string | undefined, encode: Encode, ids: HeaderTokenIds, errors?: string): number[] {
|
||||
const out = [ids.repoName, ...encode(`${repo}\n`)]
|
||||
if (context) {
|
||||
const dir = filePath.includes('/') ? filePath.slice(0, filePath.lastIndexOf('/')) : '.'
|
||||
out.push(ids.fileSep, ...encode(`${dir}/__symbols__.d.ts\n${context}\n`))
|
||||
}
|
||||
const dir = filePath.includes('/') ? filePath.slice(0, filePath.lastIndexOf('/')) : '.'
|
||||
if (context) out.push(ids.fileSep, ...encode(`${dir}/__symbols__.d.ts\n${context}\n`))
|
||||
// TS errors near the cursor (shared/diagnostics.ts), for models trained with them (Stage D+).
|
||||
if (errors) out.push(ids.fileSep, ...encode(`${dir}/__errors__.txt\n${errors}\n`))
|
||||
out.push(ids.fileSep, ...encode(`${filePath}\n`))
|
||||
return out
|
||||
}
|
||||
@@ -115,3 +115,22 @@ export function wantsSingleLine(suffix: string): boolean {
|
||||
const restOfLine = suffix.split('\n')[0]
|
||||
return /[^\s)\]}'"`;,]/.test(restOfLine)
|
||||
}
|
||||
|
||||
/**
|
||||
* Token healing for completions that start mid-identifier (`this.connections.del▮`).
|
||||
*
|
||||
* Suffix-first prompts end exactly at the cursor, so a half-typed word leaves an unnatural final token and the
|
||||
* model tends to treat the word as finished (`(relayUrl)` instead of `ete(relayUrl)`). Instead, cut the partial
|
||||
* word off the prompt and force the output to start with it (llama.cpp grammar); the caller strips it again.
|
||||
* Bonus: while typing `d`, `de`, `del` the healed prompt is identical, so the KV cache is fully reused.
|
||||
*/
|
||||
export function healPrefix(prefix: string): { prefix: string; forced: string } | null {
|
||||
const m = /(^|[^\w$])([\w$]{1,32})$/.exec(prefix)
|
||||
if (!m) return null
|
||||
return { prefix: prefix.slice(0, prefix.length - m[2].length), forced: m[2] }
|
||||
}
|
||||
|
||||
/** GBNF grammar: output must start with `forced`, then anything. */
|
||||
export function forcedPrefixGrammar(forced: string): string {
|
||||
return `root ::= "${forced.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}" rest\nrest ::= [^\\x00]*`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user