Skip to content

AI completion: remote FIM (fill-in-the-middle) provider for the web IDE #8

@JonathanTurnock

Description

@JonathanTurnock

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

  • Editor is CodeMirror 6 + Svelte 5, fully client-side, no network calls today.
  • Grammar dropdown completer: web-ide/src/lib/pseudoscript-language.js:123 (sync override).
  • WASM bridge (JSON-in/JSON-out): web-ide/src/lib/pds.js; exports incl. parse, check, outline.
  • 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`).
  • "AI Completion" tab in web-ide/src/lib/components/Settings.svelte: masked key, endpoint, model, on/off. Sane defaults.

Phase 2 — Provider-agnostic FIM client

  • 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.

Phase 4 — Inline ghost-text extension

  • New web-ide/src/lib/inline-completion.js: ViewPlugin + Decoration.widget greyed text, keymap (Tab accept / Esc dismiss), debounced idle trigger (~300–500ms).
  • Wire into languageBundle() at web-ide/src/lib/components/Editor.svelte:554, gated on llm.enabled.

Phase 5 — Validation + robustness

  • Splice suggestion at cursor, run WASM parse, drop hard syntax breakage (lenient on static warnings).
  • Debounce, cancel-on-keystroke, swallow network errors (must never block typing), handle unconfigured state.

Phase 6 — Polish

  • 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.
  • Could split into sub-tasks per phase (cf. Lineage epic Data lineage canvas for the web IDE #1).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions