AI inline suggest / ghost text
Copilot-style ghost text autocomplete in any Koder editor surface. Dimmed inline suggestion + Tab/→ to accept + Esc to discard + partial-accept (word/line). Debounce 300ms. Sandbox-isolated streaming from services/ai/gateway. Required for Kode editor, Kortex notebook, future Kanvas.
Spec — AI inline suggest / ghost text
Pattern: GitHub Copilot ghost text + VS Code Next Edit Suggestions. Streams via
streaming-text.kmd. Cost transparency viacost-display.kmd(#112).
Princípios
- *ubtle by default*— dimmed (50% opacity) ghost text inline; non-intrusive.
- *ast acceptance*— Tab/→ accepts full; Cmd+→ word; Cmd+Shift+→ line.
- *asy dismiss*— Esc OR any keystroke (other than accept keys) cancels.
- *ebounced trigger*— 300ms default after typing pauses.
- *ost-aware*— every suggestion has token attribution; surfaced in status bar.
R1 — Visual
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)█ ← ghost suggestion (dimmed)
▲
cursor- Color:
textat 50% opacity (perthemes/color-roles.kmd). - Font: same as editor body (preserve metrics).
- Background: NONE (transparent overlay).
- Underline: NONE.
When cursor moves through ghost → ghost text moves accordingly (anchored to cursor position).
R2 — Trigger
| Condition | Action |
|---|---|
| User types → pause 300ms | Trigger suggestion request |
| User keeps typing | Cancel pending request |
| Cursor moves | Cancel current ghost |
| Window blurs | Cancel current ghost |
Debounce configurable peruser (200500ms range).
R3 — Accept modes
| Key | Action |
|---|---|
| Tab | Accept full suggestion |
| → (arrow right) | Accept full (alternative — configurable per-OS) |
| Cmd/Ctrl + → | Accept next word |
| Cmd/Ctrl + Shift + → | Accept next line |
| Esc | Discard suggestion |
| Any printable key | Discard + new input |
Partial accept advances cursor; remaining ghost stays.
R4 — Backend integration
Request via services/ai/gateway:
{
"type": "inline_suggest",
"prefix": "...lines before cursor...",
"suffix": "...lines after cursor...",
"language": "python",
"file_path": "lib/math.py",
"max_tokens": 128,
"stop_sequences": ["\n\n"]
}Stream response tokenbytoken (crosslink `streamingtext.kmd`):
- First token within ~500ms (model SLA — surface in cost-display).
- Display starts rendering at first token.
- Cancel on any user keystroke after first token already shown.
R5 — Cost transparency
Per-suggestion cost surfaced in editor status bar:
[Editor] · 12 lines · 250 in/45 out · $0.0008Aggregate session cost via cost-display.kmd (#112).
R6 — Surface enable/disable
User toggle in editor settings:
- *nabled*(default): ghost suggestions appear.
- *isabled* no requests sent.
- *anual trigger*(Ctrl+Space): only on demand.
Workspacelevel + userlevel + perfile setting; perfile > workspace > user > stack default.
R7 — Context window
Gateway receives prefix + suffix:
- Prefix: last N lines before cursor (default 50).
- Suffix: next M lines after cursor (default 10).
- File path + language hint per LSP protocol.
Truncated by model context limit — surface warning if file too large for current model.
R8 — Surface bindings
| Surface | API |
|---|---|
| Flutter | KoderGhostTextField({onSuggestionAccept, model, gateway}) em koder_kit/lib/src/ai/ghost_text_field.dart |
| Web | <koder-ghost-text-input> (CodeMirror/Monaco extension recommended) |
| Compose/SwiftUI | futuro |
| Vim / Emacs | LSP server (koder-lsp-suggest) |
R9 — Acessibilidade
- Ghost text:
aria-hidden="true"(não anuncia continuously); accept = announce "Suggestion accepted: text". - Keyboard shortcuts: documented in
aria-keyshortcuts. - Reduced
motion: ghost appears instant (no fadein). - Screen reader users: configurable mode "announce all suggestions" (default OFF — noise).
R10 — i18n
| Key | en-US | pt-BR |
|---|---|---|
ai.suggest.setting.enabled |
"AI suggestions" | "Sugestões de IA" |
ai.suggest.setting.manual |
"Manual trigger only" | "Ativar manualmente" |
ai.suggest.accept.full |
"Suggestion accepted" | "Sugestão aceita" |
ai.suggest.accept.partial |
"Partial suggestion accepted" | "Parte da sugestão aceita" |
ai.suggest.cost.label |
"{in}/{out} · {cost}" | "{in}/{out} · {cost}" |
R11 — Multi-tenant
Per-file storage/cost attribution per (koder_user_id, workspace_id, file_id).
T-suite
- *1*Trigger: type + pause 300ms → suggestion appears.
- *2*Accept full: Tab → ghost text inserted; cursor at end.
- *3*Accept word: Cmd+→ → only next word inserted; remaining stays ghost.
- *4*Accept line: Cmd+Shift+→ → only next line; remaining stays.
- *5*Esc dismisses: ghost gone.
- *6*Other keystroke dismisses: user types → ghost gone; new trigger debounce starts.
- *7*Cursor move cancels: arrow key → ghost gone.
- *8*Disable: setting OFF → no requests sent.
- *9*Manual trigger: setting "manual" + Ctrl+Space → suggestion appears.
- *10*Cost surfaced: each suggestion → status bar updates with cost.
- *11*Streaming: first token < 500ms (SLA gate via model registry).
- *12*A11y reduced-motion: ghost appears instant.
- *1*Large file: file > model context → warning surfaced; suggestions disabled until model switch.
Cross-link
- Companion:
streaming-text.kmd(R4 streaming integration),cost-display.kmd(R5 status bar),model-selector.kmd(model switch affects suggestion quality) - Backend:
services/ai/gateway/ - Consumers:
products/dev/kdev, futureproducts/dev/kanvas, Kortex notebook - Refs: GitHub Copilot ghost text, VS Code Next Edit Suggestions