Skip to content

前回までにやってきたこと#

  • VSCode Extension開発環境のセットアップ
  • package.jsonにviews設定を追加してWebviewを有効化

今回やること#

  • WebViewにtextareaとボタンを追加してユーザーインターフェースを作成
  • vscode.lm APIを使ったLLMとの通信機能を実装
  • ユーザー入力に対するLLMの応答表示機能を追加
  • 基本的なチャット機能を完成

VSCode Extension AI Agent作成 - VSCode LM API連携#

WebViewにtextareaを追加し、vscode.lm APIでLLMを呼び出していきましょう!

前のファイルからWebViewに表示するHTMLを変更します src/extension.tsを以下のように変更してください。

import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
    const provider = new MagiViewProvider();
    context.subscriptions.push(
        vscode.window.registerWebviewViewProvider(
            "main.view",
            provider,
        ),
    );
}
class MagiViewProvider implements vscode.WebviewViewProvider {

    public async resolveWebviewView(webviewView: vscode.WebviewView) {
        webviewView.webview.options = {
            enableScripts: true,
        };

//ここから挿入
        webviewView.webview.onDidReceiveMessage(async (data) => {
            if (data.type === 'promptEntered') {
                webviewView.webview.postMessage({
                    type: 'addElement',
                    text: data.text
                });

                const models = await vscode.lm.selectChatModels({ vendor: 'copilot', family: 'gpt-4.1' });
                const model = models[0];
                const messages = [vscode.LanguageModelChatMessage.User(data.text)];
                const response = await model.sendRequest(messages);

                let returnTextFromVscodeLm = '';
                for await (const fragment of response.text) {
                    returnTextFromVscodeLm += fragment;
                }
                webviewView.webview.postMessage({
                    type: 'addElement',
                    text: returnTextFromVscodeLm
                });
//ここまで挿入
            }
        });
        webviewView.webview.html = `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Agent</title>
</head>
<body>
    Hello World!
<!-- ここから挿入 -->
    <textarea id="input-textarea" data-testid="input-textarea" rows="4" style="width:100%" placeholder="Enter text and press Enter..."></textarea>
    <div id="output" data-testid="output"></div>

    <script>
        const vscode = acquireVsCodeApi();
        const textarea = document.getElementById('input-textarea');
        const output = document.getElementById('output');

        textarea.addEventListener('keydown', function(event) {
            // Enterキーが押された時
            if (event.key === 'Enter') {
                // IMEの変換中(composing状態)でない場合のみ処理
                if (!event.isComposing) {
                    event.preventDefault(); // デフォルトの改行を防ぐ

                    const text = textarea.value.trim();
                    if (text) {
                        // VS Codeにメッセージを送信
                        vscode.postMessage({
                            type: 'promptEntered',
                            text: text
                        });
                        textarea.value = '';
                    }
                }
            }
        });

        // VS Codeからのメッセージを受け取る
        window.addEventListener('message', event => {
            const message = event.data;
            if (message.type === 'addElement') {
                const newDiv = document.createElement('div');
                newDiv.textContent = message.text;
                output.appendChild(newDiv);
            }
        });

        // composition系のイベントも念のため処理
        let isComposing = false;
        textarea.addEventListener('compositionstart', function() {
            isComposing = true;
        });
        textarea.addEventListener('compositionend', function() {
            isComposing = false;
        });
    </script>
<!-- ここまで挿入 -->
</body>
</html>`;
    }
}

動かしてみる。#

npm run compile

でプロジェクトをビルドしてから、 Visual Studio CodeのメニューのRun→Start Debuggingを押すと新しくVisuao Studio Codeが立ち上がります。 すでにExtensionを立ち上げている場合はソースを表示しているVisual Studio Codeの runbar で、再起動矢印を押すと反映されます。

textareaに入力してEnterキーを押すと、生成AIが応答して画面に表示されます。 お手軽に生成AIをアプリケーションに取り込めるのは素晴らしいですね!

コードの解説#

要点を解説していきます。

vscode.lm#

vscode.lm APIを使うことで、Visual Studio Codeの拡張機能からLLM(大規模言語モデル)にアクセスできます。 このサンプルでは selectChatModels({ vendor: 'copilot', family: 'gpt-4.1' }) でCopilotのGPT-4.1モデルを選択していますが、API自体は他のベンダーやモデルファミリーも選択できます。 用途や必要に応じて、利用可能なモデル一覧から選択して使ってください。。

UI→バックエンド通信 vscode.postMessage/webviewView.webview.onDidReceiveMessage#

VSCode拡張のWebViewでは、UI(フロントエンド)とバックエンド(拡張本体)は分離されています。 UIからバックエンドに処理を依頼するには、vscode.postMessage でメッセージを送信し、バックエンド側で webviewView.webview.onDidReceiveMessage で受信します。 vscode.lm APIはバックエンドで利用できるため、LLMへの問い合わせは必ずバックエンドで行い、その結果をUIに返すようにしています。

バックエンド→UI通信 webviewView.webview.postMessage/window.addEventListener#

バックエンドからUIへデータを返すには、webviewView.webview.postMessage を使ってメッセージを送信します。 UI側では window.addEventListener('message', ...) で受信し、受け取った内容を画面に反映します。 この仕組みにより、LLMの応答などバックエンドで取得したデータをUIに表示できます。

今回やったこと#

LLMをアプリケーションに組み込むことができました。意外と簡単だったのでは? - HTMLにtextarea、メッセージ表示エリアを追加 - JavaScript側でユーザー入力とメッセージ受信の処理を実装 - vscode.lm APIを使ってLLMとの通信機能を実装 - 基本的なチャット機能が動作することを確認

次にやること#

次はLLMに機能を提供して、生成AIがコードを書けるようにします。