Skip to main content

Overview

The AI Suggestions API provides intelligent code completion and editing capabilities. Get real-time code suggestions as you type or quickly edit selected code with natural language instructions.

Code Suggestion

/api/suggestion
POST
Get AI-powered code completion at cursor position

Request Body

fileName
string
required
Name of the file being edited (used for context)
code
string
required
The full code content of the file
currentLine
string
required
The current line where the cursor is located
lineNumber
number
required
Line number of the cursor (1-based)
textBeforeCursor
string
required
Text before cursor position on the current line
textAfterCursor
string
required
Text after cursor position on the current line
previousLines
string
Previous lines for context (optional)
nextLines
string
Next lines for context (optional)

Response

suggestion
string
The suggested code to insert at cursor position, or empty string if no suggestion

Example Request

cURL
curl -X POST https://your-domain.com/api/suggestion \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{
    "fileName": "App.jsx",
    "code": "import React from '\''react'\'';\n\nfunction App() {\n  const [count, setCount] = \n}",
    "currentLine": "  const [count, setCount] = ",
    "lineNumber": 4,
    "textBeforeCursor": "  const [count, setCount] = ",
    "textAfterCursor": "",
    "previousLines": "import React from '\''react'\'';\n\nfunction App() {",
    "nextLines": "}"
  }'
JavaScript
const response = await fetch('/api/suggestion', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${token}`
  },
  body: JSON.stringify({ 
    fileName: 'App.jsx',
    code: fullCode,
    currentLine: '  const [count, setCount] = ',
    lineNumber: 4,
    textBeforeCursor: '  const [count, setCount] = ',
    textAfterCursor: '',
    previousLines: 'import React from \'react\';\n\nfunction App() {',
    nextLines: '}'
  })
});

const { suggestion } = await response.json();

Example Response

Success
{
  "suggestion": "useState(0);"
}
No Suggestion
{
  "suggestion": ""
}

Error Codes

  • 400 - Missing required field (code is required)
  • 403 - Unauthorized
  • 500 - Failed to generate suggestion

Suggestion Logic

The AI follows these rules:
  1. Check next lines: If code already exists after cursor, return empty string
  2. Check completion: If line ends with complete statement (;, }, )), return empty string
  3. Generate suggestion: Only suggest if incomplete and no code exists ahead
Suggestions are designed to be non-intrusive. They only appear when the AI is confident the code needs completion and won’t duplicate existing code.

Quick Edit

/api/quick-edit
POST
Edit selected code using natural language instruction (Cmd+K functionality)

Request Body

selectedCode
string
required
The code that is currently selected for editing
instruction
string
required
Natural language instruction describing the desired changes
fullCode
string
The full file content for context (optional but recommended)

Response

editedCode
string
The edited version of the selected code (or original if instruction unclear)

Example Request

cURL
curl -X POST https://your-domain.com/api/quick-edit \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{
    "selectedCode": "function add(a, b) {\n  return a + b;\n}",
    "instruction": "add JSDoc comments",
    "fullCode": "function add(a, b) {\n  return a + b;\n}\n\nconsole.log(add(1, 2));"
  }'
JavaScript
const response = await fetch('/api/quick-edit', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${token}`
  },
  body: JSON.stringify({ 
    selectedCode: 'function add(a, b) {\n  return a + b;\n}',
    instruction: 'add JSDoc comments',
    fullCode: fullFileContent
  })
});

const { editedCode } = await response.json();

Example Response

Success
{
  "editedCode": "/**\n * Adds two numbers together\n * @param {number} a - First number\n * @param {number} b - Second number\n * @returns {number} Sum of a and b\n */\nfunction add(a, b) {\n  return a + b;\n}"
}

Error Codes

  • 400 - Missing selected code or instruction
  • 400 - Unauthorized (note: returns 400, not 403)
  • 500 - Failed to generate edit

Documentation Integration

Quick edit can automatically fetch and use documentation from URLs in the instruction:
Example with URL
const response = await fetch('/api/quick-edit', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${token}`
  },
  body: JSON.stringify({ 
    selectedCode: 'const data = []',
    instruction: 'Convert to use Zustand store according to https://docs.pmnd.rs/zustand',
    fullCode: fullFileContent
  })
});
The API will:
  1. Extract URLs from the instruction (regex: https?://[^\s)>\]]+)
  2. Scrape documentation using Firecrawl (if configured)
  3. Include scraped content in the prompt
  4. Generate code following the documentation
URL scraping requires FIRECRAWL_API_KEY environment variable. Without it, URLs in instructions are ignored.

AI Configuration

Temperature and Tokens

Both endpoints use these AI parameters:
  • Temperature: 0.7 (balanced creativity)
  • Suggestion max tokens: 500
  • Quick edit max tokens: 2000

Provider Fallback

Both endpoints use the generateWithFallback function:
  1. Primary: Moonshot AI Kimi K2.5 via OpenRouter (via OPENROUTER_API_KEY)
  2. Fallback: Cerebras GLM-4.7 (via CEREBRAS_API_KEY)
If the primary provider fails, the system automatically retries with the fallback.

Integration Examples

CodeMirror Extension

CodeMirror Extension
import { ViewPlugin } from '@codemirror/view';
import { debounce } from 'lodash';

const suggestionPlugin = ViewPlugin.fromClass(class {
  constructor(view) {
    this.view = view;
    this.fetchSuggestion = debounce(this.getSuggestion.bind(this), 500);
  }
  
  update(update) {
    if (update.docChanged || update.selectionSet) {
      this.fetchSuggestion();
    }
  }
  
  async getSuggestion() {
    const { state } = this.view;
    const cursor = state.selection.main.head;
    const line = state.doc.lineAt(cursor);
    
    const response = await fetch('/api/suggestion', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      },
      body: JSON.stringify({
        fileName: currentFileName,
        code: state.doc.toString(),
        currentLine: line.text,
        lineNumber: line.number,
        textBeforeCursor: state.sliceDoc(line.from, cursor),
        textAfterCursor: state.sliceDoc(cursor, line.to),
        previousLines: getPreviousLines(state, line),
        nextLines: getNextLines(state, line)
      })
    });
    
    const { suggestion } = await response.json();
    
    if (suggestion) {
      // Show ghost text suggestion
      this.showSuggestion(suggestion);
    }
  }
});

Quick Edit Keybinding

Quick Edit Integration
import { keymap } from '@codemirror/view';

const quickEditKeymap = keymap.of([{
  key: 'Mod-k', // Cmd+K on Mac, Ctrl+K on Windows/Linux
  run: async (view) => {
    const { state } = view;
    const selection = state.selection.main;
    const selectedCode = state.sliceDoc(selection.from, selection.to);
    
    if (!selectedCode) return false;
    
    const instruction = await showInputDialog('What would you like to do?');
    if (!instruction) return false;
    
    const response = await fetch('/api/quick-edit', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      },
      body: JSON.stringify({
        selectedCode,
        instruction,
        fullCode: state.doc.toString()
      })
    });
    
    const { editedCode } = await response.json();
    
    // Replace selection with edited code
    view.dispatch({
      changes: {
        from: selection.from,
        to: selection.to,
        insert: editedCode
      }
    });
    
    return true;
  }
}]);

Best Practices

Avoid sending a request on every keystroke. Use debouncing (300-500ms) to reduce API calls.
Always send previousLines and nextLines for better suggestions. More context = better results.
Empty suggestions are normal and expected. Don’t show any UI when suggestion === "".
Cache suggestions for identical cursor positions to avoid redundant API calls.
For quick edit, show a loading indicator while processing. The operation can take 1-3 seconds.

Rate Limiting

Suggestions and quick edits use your configured AI provider’s rate limits:
  • OpenRouter (Kimi K2.5): Depends on your OpenRouter plan
  • Cerebras (GLM-4.7): 30 requests/min (free tier)
Consider implementing client-side throttling for heavy usage.

Next Steps

Messages API

Build conversational AI features

Projects API

Create and manage projects

Build docs developers (and LLMs) love