Files
MCPletA2A/reference_impl/agents/info-gathering/index.ts
2026-03-30 17:39:13 +09:00

110 lines
4.0 KiB
TypeScript

/**
* 情報収集・分析 Agent
*
* accessiblePools: [info-pool]
* 利用可能ツール: fetch_web_content (info-pool), call_external_api (info-pool),
* query_crm (pool-less), query_erp (pool-less), query_hr (pool-less)
*
* タスク: 天気予報・在庫・顧客キャンセル傾向を収集し、分析サマリを返す
*/
import type { A2ATaskRequest, A2ATaskResponse } from '../platform-types.js';
import { AgentBase } from '../agent-base.js';
export class InfoGatheringAgent extends AgentBase {
readonly agentId = 'info-gathering-agent';
readonly accessiblePools = ['info-pool'];
async handle(task: A2ATaskRequest): Promise<A2ATaskResponse> {
const instruction = (task.payload.parameters['instruction'] as string | undefined) ?? '';
const targetDate = new Date().toISOString().slice(0, 10);
try {
// 1. Collect weather forecast
const weather = await this.callTool('fetch_web_content', {
source: 'weather_forecast',
date: targetDate,
});
// 2. Collect dessert inventory via external API
const inventory = await this.callTool('call_external_api', {
api: 'inventory',
params: { item: 'dessert' },
});
// 3. Query CRM for high-cancellation-tendency customers
const customers = await this.callTool('query_crm', {
entity: 'customers',
filter: 'rain_cancel_tendency',
});
// 4. Query reservations for tomorrow
const reservations = await this.callTool('query_crm', {
entity: 'reservations',
filter: `date=${targetDate}`,
});
// 5. Synthesize analysis
const analysis = this.synthesize({ weather, inventory, customers, reservations, targetDate, instruction });
console.log(`[info-gathering] Analysis complete: ${analysis.summary}`);
return this.success(task, {
analysis,
rawData: { weather, inventory, customers, reservations },
});
} catch (err) {
return this.error(task, (err as Error).message);
}
}
private synthesize(data: {
weather: unknown;
inventory: unknown;
customers: unknown;
reservations: unknown;
targetDate: string;
instruction: string;
}): Record<string, unknown> {
const wx = data.weather as { forecasts?: Array<{ condition?: string; summary?: string; precipitationProbability?: number }> };
const forecast = wx?.forecasts?.[0];
const isRainy = forecast?.condition === 'rainy';
const precipProb = forecast?.precipitationProbability ?? 0;
const inv = data.inventory as { items?: Array<{ name?: string; stock?: number; category?: string }> };
const desserts = (inv?.items ?? []).filter((i) => i.category === 'dessert');
const hasDessertStock = desserts.some((d) => (d.stock ?? 0) > 0);
const cust = data.customers as { customers?: Array<unknown>; total?: number };
const highCancelCount = cust?.total ?? (cust?.customers?.length ?? 0);
const res = data.reservations as { reservations?: Array<unknown>; total?: number };
const reservationCount = res?.total ?? (res?.reservations?.length ?? 0);
const actionRecommended = isRainy && hasDessertStock && highCancelCount > 0;
return {
targetDate: data.targetDate,
weather: {
condition: forecast?.condition ?? 'unknown',
isRainy,
precipitationProbability: precipProb,
summary: forecast?.summary ?? '',
},
inventory: {
hasDessertStock,
dessertsAvailable: desserts.map((d) => ({ name: d.name, stock: d.stock })),
},
customers: {
highCancelTendencyCount: highCancelCount,
},
reservations: {
tomorrowCount: reservationCount,
},
actionRecommended,
summary: actionRecommended
? `明日は雨予報(${precipProb}%)で、デザート在庫あり、高キャンセル傾向顧客${highCancelCount}名・予約${reservationCount}件あり。無料デザートキャンペーンを推奨。`
: `現時点でキャンペーン実施条件が揃っていません。`,
};
}
}