Daemon: OpenAI-compatible /v1/completions for Zed
ci / build (push) Canceled after 0s

Parses Qwen-format FIM prompts (prefix- or suffix-first, optional repo/file headers) back into
prefix/suffix and rebuilds them in the trained layout; mode from the model string (ac:symbols /
ac:simple); files located via workspaceRoots by path or content. extensions/zed/README.md documents
the Zed settings; untested against real Zed traffic yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J39imRDT8L7xYbWzsVWd8A
This commit is contained in:
2026-10-03 17:25:27 +00:00
co-authored by Claude Opus 5.5
parent 87d3c3c3bf
commit 4c86c2a703
6 changed files with 151 additions and 2 deletions
+69
View File
@@ -0,0 +1,69 @@
import fs from 'node:fs'
import path from 'node:path'
/**
* Parses a FIM prompt built by another client (e.g. Zed's `open_ai_compatible_api` edit-prediction provider with
* prompt_format "qwen") back into prefix / suffix / file path, so the daemon can rebuild the prompt in the layout
* our models were trained on (suffix-first, repo header, symbols, healing).
*
* Accepts, in order of preference:
* [<|repo_name|>repo\n] [<|file_sep|>path\n …] <|fim_prefix|>{prefix}<|fim_suffix|>{suffix}<|fim_middle|>
* <|fim_prefix|><|fim_suffix|>{suffix}<|fim_middle|>{prefix} (suffix-first)
* Returns null for anything else (e.g. a plain completion prompt): the caller then treats it as prefix-only.
*/
export function parseFimPrompt(prompt: string): { prefix: string; suffix: string; path?: string; repo?: string } | null {
const repo = /<\|repo_name\|>([^\n<]*)\n/.exec(prompt)?.[1]?.trim() || undefined
const seps = [...prompt.matchAll(/<\|file_sep\|>([^\n<]*)\n/g)]
const filePath = seps.length ? seps.at(-1)![1].trim() || undefined : undefined
const psm = /<\|fim_prefix\|>([\s\S]*?)<\|fim_suffix\|>([\s\S]*?)<\|fim_middle\|>\s*$/.exec(prompt)
if (psm && !psm[1].includes('<|fim_suffix|>')) {
if (psm[1] === '') {
// Possibly suffix-first: "<pre><suf>suffix<mid>prefix"
const spm = /<\|fim_prefix\|><\|fim_suffix\|>([\s\S]*?)<\|fim_middle\|>([\s\S]*)$/.exec(prompt)
if (spm) return { prefix: spm[2], suffix: spm[1], path: filePath, repo }
}
return { prefix: psm[1], suffix: psm[2], path: filePath, repo }
}
const spm = /<\|fim_prefix\|><\|fim_suffix\|>([\s\S]*?)<\|fim_middle\|>([\s\S]*)$/.exec(prompt)
if (spm) return { prefix: spm[2], suffix: spm[1], path: filePath, repo }
return null
}
/** "ac:symbols" / "ac:simple" / "ac:raw" select the context mode; anything else keeps the current toggle. */
export function modeFromModel(model: unknown): 'symbols' | 'simple' | 'raw' | undefined {
const m = /^ac:(symbols|simple|raw)$/.exec(String(model ?? ''))
return m ? (m[1] as 'symbols' | 'simple' | 'raw') : undefined
}
/**
* Finds the workspace for a request: the root containing `relPath` (if the client sent a path), else the root
* containing a file whose content starts with the prompt's prefix (Zed may not send a path).
*/
export function locateFile(roots: string[], relPath: string | undefined, prefix: string): { root: string; path: string } | null {
if (relPath) {
for (const root of roots) {
if (path.isAbsolute(relPath) && relPath.startsWith(root + path.sep)) return { root, path: path.relative(root, relPath).split(path.sep).join('/') }
if (fs.existsSync(path.join(root, relPath))) return { root, path: relPath }
}
}
const probe = prefix.slice(0, 400)
if (probe.length < 40) return null
for (const root of roots) {
const stack = [root]
let visited = 0
while (stack.length && visited < 5000) {
const dir = stack.pop()!
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
if (e.name.startsWith('.') || e.name === 'node_modules' || e.name === 'dist') continue
const p = path.join(dir, e.name)
if (e.isDirectory()) stack.push(p)
else if (/\.(ts|tsx|js|jsx|vue|mts|cts)$/.test(e.name) && ++visited) {
try {
if (fs.readFileSync(p, 'utf8').startsWith(probe)) return { root, path: path.relative(root, p).split(path.sep).join('/') }
} catch { /* unreadable */ }
}
}
}
}
return null
}