110 lines
4.0 KiB
TypeScript
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}件あり。無料デザートキャンペーンを推奨。`
|
|
: `現時点でキャンペーン実施条件が揃っていません。`,
|
|
};
|
|
}
|
|
}
|