ラボ M3 - 新しい検索コマンドによるプラグインの拡張
このラボでは、Northwind プラグインに新しいコマンドを追加して拡張します。現在のメッセージ拡張は Northwind 在庫データベース内の製品情報を提供しますが、Northwind の顧客に関連する情報は提供しません。ここでは、 ユーザー が指定した会社名で注文された製品を取得する API 呼び出しに関連付けられた新しいコマンドを追加します。
Extend Teams Message Extension ラボのナビゲーション (Extend Path)
NOTE
すべてのコード変更を含む完成版の演習は こちら からダウンロードできます。トラブルシューティングに役立ちます。 変更をリセットしたい場合は、リポジトリを再度クローンしてやり直してください。
演習 1 - コード変更
手順 1 - メッセージ拡張 / プラグイン UI の拡張
前回のラボで作成した Northwind 作業ディレクトリ内の appPackage フォルダーにある manifest.json を開きます。
commands 配列の中で discountSearch を探します。discountSearch コマンドの閉じカッコの後ろにカンマ , を追加します。その後 companySearch コマンドのスニペットをコピーして commands 配列に追加します。
{
"id": "companySearch",
"context": [
"compose",
"commandBox"
],
"description": "Given a company name, search for products ordered by that company",
"title": "Customer",
"type": "query",
"parameters": [
{
"name": "companyName",
"title": "Company name",
"description": "The company name to find products ordered by that company",
"inputType": "text"
}
]
}
COMMAND_ID
"id" は UI とコードを結び付けるキーです。この値は discount/product/SearchCommand.ts ファイルで COMMAND_ID として定義されています。各ファイルには固有の COMMAND_ID があり、"id" の値と対応しています。
手順 2 - 会社名による製品検索の実装
会社名で製品を検索し、その会社が注文した製品の一覧を返す機能を実装します。以下のテーブルを参考にしてください。
| Table | 検索対象 | 参照キー |
|---|---|---|
| Customer | Customer Id | Customer Name |
| Orders | Order Id | Customer Id |
| OrderDetail | Product | Order Id |
動作概要:
Customer テーブルで Customer Name から Customer Id を取得します。次に Orders テーブルで Customer Id を使って関連する Order Id を取得します。各 Order Id について、OrderDetail テーブルで関連製品を取得します。最後に、指定した会社名が注文した製品の一覧を返します。
.\src\northwindDB\products.ts を開きます。
1 行目の import 文を更新して OrderDetail, Order, Customer を含めます。次のようになります。
import {
TABLE_NAME, Product, ProductEx, Supplier, Category, OrderDetail,
Order, Customer
} from './model';
import { getInventoryStatus } from '../adaptiveCards/utils'; の直後に、下記スニペットのとおり searchProductsByCustomer() 関数を追加します。
export async function searchProductsByCustomer(companyName: string): Promise<ProductEx[]> {
let result = await getAllProductsEx();
let customers = await loadReferenceData<Customer>(TABLE_NAME.CUSTOMER);
let customerId="";
for (const c in customers) {
if (customers[c].CompanyName.toLowerCase().includes(companyName.toLowerCase())) {
customerId = customers[c].CustomerID;
break;
}
}
if (customerId === "")
return [];
let orders = await loadReferenceData<Order>(TABLE_NAME.ORDER);
let orderdetails = await loadReferenceData<OrderDetail>(TABLE_NAME.ORDER_DETAIL);
// build an array orders by customer id
let customerOrders = [];
for (const o in orders) {
if (customerId === orders[o].CustomerID) {
customerOrders.push(orders[o]);
}
}
let customerOrdersDetails = [];
// build an array order details customerOrders array
for (const od in orderdetails) {
for (const co in customerOrders) {
if (customerOrders[co].OrderID === orderdetails[od].OrderID) {
customerOrdersDetails.push(orderdetails[od]);
}
}
}
// Filter products by the ProductID in the customerOrdersDetails array
result = result.filter(product =>
customerOrdersDetails.some(order => order.ProductID === product.ProductID)
);
return result;
}
手順 3 - 新しいコマンド用のハンドラー作成
VS Code で src/messageExtensions フォルダーにある productSearchCommand.ts を複製し、コピーしたファイルの名前を customerSearchCommand.ts に変更します。
COMMAND_ID 定数の値を次のように変更します。
const COMMAND_ID = "companySearch";
以下の import 文を:
import { searchProducts } from "../northwindDB/products";`
から
import { searchProductsByCustomer } from "../northwindDB/products";
へ置き換えます。
handleTeamsMessagingExtensionQuery の既存の波かっこ内のコードを下記スニペットに置き換えます。
let companyName;
// Validate the incoming query, making sure it's the 'companySearch' command
// The value of the 'companyName' parameter is the company name to search for
if (query.parameters.length === 1 && query.parameters[0]?.name === "companyName") {
[companyName] = (query.parameters[0]?.value.split(','));
} else {
companyName = cleanupParam(query.parameters.find((element) => element.name === "companyName")?.value);
}
console.log(`🍽️ Query #${++queryCount}:\ncompanyName=${companyName}`);
const products = await searchProductsByCustomer(companyName);
console.log(`Found ${products.length} products in the Northwind database`)
const attachments = [];
products.forEach((product) => {
const preview = CardFactory.heroCard(product.ProductName,
`Customer: ${companyName}`, [product.ImageUrl]);
const resultCard = cardHandler.getEditCard(product);
const attachment = { ...resultCard, preview };
attachments.push(attachment);
});
return {
composeExtension: {
type: "result",
attachmentLayout: "list",
attachments: attachments,
},
};
手順 4 - コマンドルーティングの更新
この手順では、companySearch コマンドを前手順で実装したハンドラーにルーティングします。
src フォルダーにある searchApp.ts を開き、次の import 文を追加します。
import customerSearchCommand from "./messageExtensions/customerSearchCommand";
handleTeamsMessagingExtensionQuery ハンドラー関数の switch 文に、以下の case 文を追加します。
case customerSearchCommand.COMMAND_ID: {
return customerSearchCommand.handleTeamsMessagingExtensionQuery(context, query);
}
Note
メッセージ拡張 / プラグインを UI で操作するときは、このコマンドが明示的に呼び出されます。しかし、Microsoft 365 Copilot から呼び出される場合は、Copilot オーケストレーターによってトリガーされます。
演習 2 - アプリを実行! 会社名で製品を検索
これで、Microsoft 365 Copilot のプラグインとしてサンプルをテストできる準備が整いました。
手順 1: 更新したアプリをローカルで実行
ローカルデバッガーが実行中の場合は停止します。新しいコマンドで manifest を更新したため、新しいパッケージでアプリを再インストールする必要があります。
appPackage フォルダー内の manifest.json で version を "1.0.9" から "1.0.10" に更新します。これによりアプリの変更が反映されます。
F5 キーを押すか、スタートボタン 1️⃣ をクリックしてデバッガーを再起動します。デバッグ プロファイルを選択する画面が表示されるので、Debug in Teams (Edge) 2️⃣ か別のプロファイルを選択します。

デバッグを開始するとブラウザー ウィンドウで Teams が開きます。Agents Toolkit にサインインしたのと同じ資格情報でログインしてください。
Teams が開くと、アプリを開くかどうかのダイアログが表示されます。

開くとすぐに、アプリをどこで開くか尋ねられます。既定では Personal Chat ですが、チャネルまたはグループ チャットも選択できます。「Open」を選択します。

これでアプリとのパーソナル チャットに入ります。ただし、今回は Copilot でテストするので次の手順に従ってください。
Teams で Chat をクリックし、Copilot を選択します。Copilot が最上部に表示されます。
Plugin アイコン をクリックし、Northwind Inventory を選択してプラグインを有効にします。
手順 2: Copilot で新しいコマンドをテスト
次のプロンプトを入力します。
What are the products ordered by 'Consolidated Holdings' in Northwind Inventory?
ターミナル出力には Copilot がクエリを理解し、会社名を抽出して companySearch コマンドを実行したことが表示されます。

Copilot での出力例:

他にも次のプロンプトを試せます。
What are the products ordered by 'Consolidated Holdings' in Northwind Inventory? Please list the product name, price and supplier in a table.
手順 3: メッセージ拡張としてコマンドをテスト (オプション)
もちろん、この新しいコマンドをメッセージ拡張としてもテストできます。前のラボと同様です。
- Teams のサイドバーで Chats に移動し、任意のチャットを開くか新しいチャットを開始します。
-
- アイコンをクリックして Apps セクションにアクセスします。
- Northwind Inventory アプリを選択します。
- Customer という新しいタブが追加されていることを確認します。
- Consolidated Holdings を検索し、この会社が注文した製品を確認します。Copilot が前手順で返した結果と一致します。

おめでとうございます
これでプラグインチャンピオンになりました。次は認証でプラグインを保護します。次のラボに進み、「Next」を選択してください。