GitHub Copilotのプロンプトファイル機能を試してみた

プロンプトファイル機能とは

プロンプトファイルを作成して、VS CodeのCopilot ChatやCopilot Editsでプロンプトを再利用できる機能です。(Reusable prompt files

プロンプトを再利用することで、チーム開発でCopilotのナレッジがたまり、活用が促進されやすくなるでしょう。

※25/2時点ではプロンプトファイル機能は試験的な機能です。

プロンプトファイル機能の使い方

プロンプトファイル機能の使い方は次のとおりです。

  1. VS Codeのchat.promptFilestrue にする
  2. .github/prompts ディレクトリ配下に.prompt.md拡張子でプロンプトファイルを作成する
  3. Copilot Chat や Copilot Editsのクリップアイコンで「Prompt...」をクリックし、プロンプトファイルを選択する
  4. チャットを実行する

プロンプトファイル機能を試してみた

1. VS Codeのchat.promptFilestrue にする

VS Codeの設定ファイルを開き、"chat.promptFiles": trueを追加します。

これで、VS Codeでプロンプトファイル機能が有効化されます。

デフォルトでは.github/prompts配下のプロンプトファイルが対象になります。

{
  // ...

  // プロンプト機能を有効化
   "chat.promptFiles": true
}

2. .github/promptsディレクトリ配下に.prompt.md拡張子でプロンプトファイルを作成する

プロンプトファイルを作成します。マークダウン形式で記載します。

今回は、「Reactのフォームコンポーネントを作成するプロンプトファイル」を追加しました。

新しいReactのフォームコンポーネントを作成してください。

フォーム名やフィールドが提供されていない場合は、確認してください。

フォームの要件:

- フォームデザインシステムのコンポーネントを使用する: design-system/Form.md
- フォームの状態管理には `react-hook-form` を使用する
  - フォームのデータに対して、必ず TypeScript の型を定義する
  - 不要な再レンダリングを防ぐために `defaultValues` を使用する
- バリデーションには `zod` を使用する:
  - 再利用可能なバリデーションスキーマを別ファイルに作成する
  - TypeScript の型を使用して型安全性を確保する
  - ユーザーエクスペリエンスに配慮したバリデーションルールをカスタマイズする

3. Copilot Chat や Copilot Editsのクリップアイコンで「Prompt...」をクリックし、プロンプトファイルを選択する

Copilot Editsのクリップアイコンを押して、「Prompt...」を選択します。

プロンプトファイルの一覧が表示されるので、すると先ほど作成したreact-form を選択します。

プロンプトがコンテキストして選択されるので、必要な情報をテキストで追加します。

4. チャットを実行する

チャットを実行すると、Contactフォームを作成してくれます。

Copilot Editsのチャットを実行

作成されたファイルは次のとおりです。

プロンプトで指定したとおり React Hook Form でフォームが作成されており、スキーマも別ファイルで作成してくれています。

import React from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { contactSchema, ContactFormData } from '../validation/contactSchema';
import { Form, Input, TextArea, Button } from 'design-system/Form';

const ContactForm: React.FC = () => {
  const { register, handleSubmit, formState: { errors } } = useForm<ContactFormData>({
    resolver: zodResolver(contactSchema),
    defaultValues: {
      email: '',
      name: '',
      message: '',
    },
  });

  const onSubmit = (data: ContactFormData) => {
    console.log(data);
  };

  return (
    <Form onSubmit={handleSubmit(onSubmit)}>
      <Input
        label="Email"
        {...register('email')}
        error={errors.email?.message}
      />
      <Input
        label="Name"
        {...register('name')}
        error={errors.name?.message}
      />
      <TextArea
        label="Message"
        {...register('message')}
        error={errors.message?.message}
      />
      <Button type="submit">Submit</Button>
    </Form>
  );
};

export default ContactForm;
import * as z from 'zod';

export const contactSchema = z.object({
  email: z.string().email({ message: "Invalid email address" }),
  name: z.string().min(1, { message: "Name is required" }),
  message: z.string().min(1, { message: "Message is required" }),
});

export type ContactFormData = z.infer<typeof contactSchema>;