/** * 情報収集・分析 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 { 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 { 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; total?: number }; const highCancelCount = cust?.total ?? (cust?.customers?.length ?? 0); const res = data.reservations as { reservations?: Array; 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}件あり。無料デザートキャンペーンを推奨。` : `現時点でキャンペーン実施条件が揃っていません。`, }; } }