You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add Copilot-style inline ghost-text completion to the web IDE, backed by a remote, provider-agnostic FIM (fill-in-the-middle) LLM. Sits beside the existing grammar dropdown completer — structural candidates stay local and deterministic; the LLM only supplies multi-token / next-line suggestions.
GitHub Copilot itself is not viable: no public completion API, gated behind a Copilot subscription + GitHub OAuth and served through their own LSP. We mimic the pattern with an open, OpenAI-compatible provider (hosted or local Ollama).
Current state
Editor is CodeMirror 6 + Svelte 5, fully client-side, no network calls today.
No credential/settings store yet (keybindings store is the pattern: web-ide/src/lib/keybindings.svelte.js:70).
Key constraint
CodeMirror 6 has no native inline/ghost-text completion — @codemirror/autocomplete only does the dropdown. Greyed inline text must be a custom ViewPlugin + decoration (recommended, ~150 lines) or a community package. This is the largest single item.
No Rust/WASM changes needed for v1 — FIM is a JS-side network call; validation reuses the existing parse/check exports.
Architecture
```
keystroke (idle) -> assemble context -> FIM client -> provider adapter -> HTTP
|
ghost text <- validate (wasm parse) <- raw completion
```
Plan
Phase 1 — Settings store + UI
New web-ide/src/lib/llm.svelte.js, localStorage-backed. Fields: enabled, baseUrl, apiKey, model, mode (`fim`|`chat`).
New web-ide/src/lib/fim-provider.js. Adapter interface complete({prefix, suffix, signal}) -> string.
Two adapters: FIM (Codestral/DeepSeek /v1/fim/completions) and chat (OpenAI-compatible /v1/chat/completions, FIM-shaped prompt). One OpenAI-compatible client covers OpenRouter / Together / Ollama / vLLM.
AbortController per request; cancel on next keystroke.
Phase 3 — Context assembly + grammar primer
Prefix/suffix from the doc around the cursor, windowed.
Cached primer: compact LANG.md §10 grammar summary + 1–2 worked examples + in-scope symbols (reuse outline/outline_modules). This is what makes a general model emit valid .pds.
Status indicator, error/empty states, request timeout.
Open decisions
Key storage: browser-only BYO key in localStorage (zero infra, key exposed to page — acceptable for a dev tool) vs a proxy holding the key (safer, infra + inference cost).
Default provider: local Ollama (free/private, needs install) vs hosted Codestral/OpenRouter (instant, needs key). Affects defaults/docs, not architecture.
Scope notes
All frontend; no breaking changes. Existing grammar completion, linting, symbol resolution unchanged.
Summary
Add Copilot-style inline ghost-text completion to the web IDE, backed by a remote, provider-agnostic FIM (fill-in-the-middle) LLM. Sits beside the existing grammar dropdown completer — structural candidates stay local and deterministic; the LLM only supplies multi-token / next-line suggestions.
GitHub Copilot itself is not viable: no public completion API, gated behind a Copilot subscription + GitHub OAuth and served through their own LSP. We mimic the pattern with an open, OpenAI-compatible provider (hosted or local Ollama).
Current state
web-ide/src/lib/pseudoscript-language.js:123(syncoverride).web-ide/src/lib/pds.js; exports incl.parse,check,outline.web-ide/src/lib/keybindings.svelte.js:70).Key constraint
CodeMirror 6 has no native inline/ghost-text completion —
@codemirror/autocompleteonly does the dropdown. Greyed inline text must be a customViewPlugin+ decoration (recommended, ~150 lines) or a community package. This is the largest single item.No Rust/WASM changes needed for v1 — FIM is a JS-side network call; validation reuses the existing
parse/checkexports.Architecture
```
keystroke (idle) -> assemble context -> FIM client -> provider adapter -> HTTP
|
ghost text <- validate (wasm parse) <- raw completion
```
Plan
Phase 1 — Settings store + UI
web-ide/src/lib/llm.svelte.js, localStorage-backed. Fields:enabled,baseUrl,apiKey,model,mode(`fim`|`chat`).web-ide/src/lib/components/Settings.svelte: masked key, endpoint, model, on/off. Sane defaults.Phase 2 — Provider-agnostic FIM client
web-ide/src/lib/fim-provider.js. Adapter interfacecomplete({prefix, suffix, signal}) -> string./v1/fim/completions) and chat (OpenAI-compatible/v1/chat/completions, FIM-shaped prompt). One OpenAI-compatible client covers OpenRouter / Together / Ollama / vLLM.AbortControllerper request; cancel on next keystroke.Phase 3 — Context assembly + grammar primer
LANG.md §10grammar summary + 1–2 worked examples + in-scope symbols (reuseoutline/outline_modules). This is what makes a general model emit valid.pds.Phase 4 — Inline ghost-text extension
web-ide/src/lib/inline-completion.js:ViewPlugin+Decoration.widgetgreyed text, keymap (Tabaccept /Escdismiss), debounced idle trigger (~300–500ms).languageBundle()atweb-ide/src/lib/components/Editor.svelte:554, gated onllm.enabled.Phase 5 — Validation + robustness
parse, drop hard syntax breakage (lenient on static warnings).Phase 6 — Polish
Open decisions
Scope notes