Monacopilot

repository·main·Indexed 43 days ago

https://github.com/arshad-yaseen/monacopilot

A framework-agnostic library for providing real-time, context-aware AI code completions. Version 1.2.12 features support for custom LLM models, efficient caching, and customizable completion behavior. It includes @monacopilot/core for engine logic and provider integrations, and supports cross-language API handlers for non-JS environments.

Tokens
24.4K
Snippets
85
Records
93
Agent score
54%

What's inside Monacopilot

  1. Overview of Monacopilot features

    main

    Monacopilot is a framework-agnostic tool designed to provide AI-powered code completions. Key features include:

    • Real-time Code Completions: Low-latency suggestions as you type.
    • Efficient Caching System: Optimized performance through intelligent caching.
    • Context-Aware Suggestions: Suggestions that understand the surrounding code context.
    • Customizable Completion Behavior: Ability to tune how completions are presented and triggered.
    • Custom Model Support: Support for integrating various AI models.
    • Manual Trigger Support: Ability to trigger completions manually rather than relying solely on automatic triggers.
  2. Overview of @monacopilot/core

    main

    @monacopilot/core is the foundational package for the Monacopilot ecosystem. It provides the essential functionality and shared utilities required to run the copilot engine. Its primary responsibilities include:

    • LLM Provider Integrations: Managing connections and interfaces for various Large Language Model providers.
    • Core Copilot Engine: Implementing the central logic that drives the copilot's behavior and decision-making processes.
  3. Use completionMetadata to craft LLM prompts

    main

    The completionMetadata object sent in the request body is the primary source of truth for constructing an accurate prompt. When implementing a custom handler in languages like Python, use the following fields from the metadata to provide context to your LLM:

    • language: The programming language of the current file.
    • textBeforeCursor: The code existing before the cursor position.
    • textAfterCursor: The code existing after the cursor position.

    To achieve high-quality results, use these fields to create a template that sandwiches a <cursor> marker (or similar indicator) between the surrounding code blocks.

  4. Create a Monacopilot Editor Component in Svelte

    main

    To use Monacopilot in a Svelte component, you need to load Monaco via @monaco-editor/loader, initialize the editor, and then use registerCompletion to link the editor to your API endpoint. Ensure you call .deregister() on the completion registration and .dispose() on the editor during the component's destruction to prevent memory leaks.

    <script lang="ts">
        import loader from '@monaco-editor/loader';
        import type * as Monaco from 'monaco-editor/esm/vs/editor/editor.api';
        import {registerCompletion, type CompletionRegistration} from 'monacopilot';
        import {onDestroy, onMount} from 'svelte';
    
        let editor: Monaco.editor.IStandaloneCodeEditor;
        let monaco: typeof Monaco;
        let editorContainer: HTMLElement;
        let completionRegistration: CompletionRegistration | null = null;
    
        onMount(async () => {
            // Load Monaco Editor using the loader method
            const monacoEditor = await import('monaco-editor');
            loader.config({monaco: monacoEditor.default});
            monaco = await loader.init();
    
            // Create the editor instance
            editor = monaco.editor.create(editorContainer, {
                value: "console.log('Hello from Monaco!')",
                language: 'javascript',
                theme: 'vs-dark',
            });
    
            // Register Monacopilot completion provider
            completionRegistration = registerCompletion(monaco, editor, {
                endpoint: '/api/code-completion',
                language: 'javascript',
            });
        });
    
        onDestroy(() => {
            // Clean up resources
            if (completionRegistration) {
                completionRegistration.deregister();
            }
            if (editor) {
                editor.dispose();
            }
            if (monaco) {
                monaco.editor.getModels().forEach(model => model.dispose());
            }
        });
    </script>
    
    <div bind:this="{editorContainer}" style="width: 100%; height: 600px;"></div>
  5. Implement a browser-only Monacopilot setup

    main

    You can implement Monacopilot entirely in the browser without a separate server endpoint by using the requestHandler option within registerCompletion. This bypasses the need for a dedicated backend endpoint by executing the completion logic directly in the client.

    Security Warning: This approach exposes your API keys in client-side code. It is not secure for production applications accessible to the public. Use this method only for testing, internal tools, or environments where security is not a concern. For production, use the server-side approach.

    To implement this, instantiate CompletionCopilot with your API key and provider configuration, then pass a requestHandler to registerCompletion that calls copilot.complete().

    import { registerCompletion, CompletionCopilot } from 'monacopilot';
    
    // Create the copilot instance directly in the browser
    const copilot = new CompletionCopilot('YOUR_API_KEY', {
      provider: 'mistral',
      model: 'codestral',
    });
    
    registerCompletion(monaco, editor, {
      language: 'javascript',
      // Use requestHandler instead of endpoint
      requestHandler: async ({ body }) => {
        const completion = await copilot.complete({ body });
        return completion;
      },
    });
  6. Create a completion API handler with CompletionCopilot

    main

    On your server, you need to implement an endpoint that matches the endpoint URL provided in registerCompletion. Use the CompletionCopilot class to process the request body and generate completions.

    In this example using Express.js and Mistral AI:

    1. Initialize CompletionCopilot with your API key and a configuration object specifying the provider (e.g., 'mistral') and the model (e.g., 'codestral').
    2. Create a POST route (e.g., /code-completion).
    3. Pass req.body to copilot.complete({body: req.body}).
    4. Return the resulting completion as a JSON response.
    import 'dotenv/config';
    
    import cors from 'cors';
    import express from 'express';
    import {CompletionCopilot} from 'monacopilot';
    
    const app = express();
    app.use(cors());
    app.use(express.json());
    
    const copilot = new CompletionCopilot(process.env.MISTRAL_API_KEY, {
        provider: 'mistral',
        model: 'codestral',
    });
    
    app.post('/code-completion', async (req, res) => {
        const completion = await copilot.complete({body: req.body});
    
        res.json(completion);
    });
    
    app.listen(process.env.PORT || 3000);
  7. Implement a Monacopilot API Route in Remix

    main

    You need to create a server-side route handler to process completion requests. This handler uses CompletionCopilot to interface with an AI provider (e.g., Mistral) and returns the completion to the client.

    1. Initialize CompletionCopilot with your API key and provider configuration.
    2. In the Remix action function, parse the CompletionRequestBody from the request.
    3. Call copilot.complete({body}) and return the result as JSON.
    import {json, type ActionFunctionArgs} from '@remix-run/node';
    import {CompletionCopilot, type CompletionRequestBody} from 'monacopilot';
    
    const copilot = new CompletionCopilot(process.env.MISTRAL_API_KEY, {
        provider: 'mistral',
        model: 'codestral',
    });
    
    export const action = async ({request}: ActionFunctionArgs) => {
        const body: CompletionRequestBody = await request.json();
        const completion = await copilot.complete({body});
    
        return json(completion);
    };
  8. Create a Monacopilot Editor Component

    main

    To enable AI completions in the browser, use the registerCompletion function within the onMount callback of the @monaco-editor/react component.

    Key steps:

    1. Use useRef to store the CompletionRegistration object.
    2. In handleMount, call registerCompletion(monaco, editor, options) where options includes the endpoint (your API route) and the target language.
    3. Use a useEffect cleanup function to call deregister() on the registration to prevent memory leaks or stale completions when the component unmounts.
    import {useEffect, useRef} from 'react';
    import MonacoEditor from '@monaco-editor/react';
    import {
        registerCompletion,
        type CompletionRegistration,
        type Monaco,
        type StandaloneCodeEditor,
    } from 'monacopilot';
    
    export default function Editor() {
        const completionRef = useRef<CompletionRegistration | null>(null);
    
        const handleMount = (editor: StandaloneCodeEditor, monaco: Monaco) => {
            completionRef.current = registerCompletion(monaco, editor, {
                endpoint: '/code-completion',
                language: 'javascript',
            });
        };
    
        useEffect(() => {
            return () => {
                completionRef.current?.deregister();
            };
        }, []);
    
        return <MonacoEditor language="javascript" onMount={handleMount} />;
    }