Cuong2004 commited on
Commit
8a43827
·
1 Parent(s): cdee6ab

Add integration guide for Report Generation API, detailing endpoints for generating full, markdown, and JSON reports. Update agent executor and triage routes to track tool executions and guidelines count for report generation, enhancing logging for better traceability. Ensure all tool executions are logged for report generation success.

Browse files
REPORT_API_INTEGRATION.md ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Report Generation API - Integration Guide
2
+
3
+ ## Tổng quan
4
+ API tạo báo cáo tổng hợp đầy đủ từ conversation session, bao gồm tất cả thông tin từ tools (CV top 3, RAG guidelines, triage results, hospital suggestions) mà response message thường bỏ qua.
5
+
6
+ ## Endpoints
7
+
8
+ ### 1. Generate/Get Full Report
9
+ ```
10
+ GET /api/reports/:session_id?type=full|summary|tools_only
11
+ ```
12
+
13
+ **Response:**
14
+ ```json
15
+ {
16
+ "session_id": "uuid",
17
+ "report_type": "full",
18
+ "generated_at": "2024-01-01T00:00:00Z",
19
+ "report": {
20
+ "report_content": { /* Full structured data */ },
21
+ "report_markdown": "# BÁO CÁO TỔNG HỢP..."
22
+ }
23
+ }
24
+ ```
25
+
26
+ ### 2. Get Markdown Only
27
+ ```
28
+ GET /api/reports/:session_id/markdown
29
+ ```
30
+ Trả về markdown report đã format sẵn, dễ hiển thị.
31
+
32
+ ### 3. Get JSON Only
33
+ ```
34
+ GET /api/reports/:session_id/json
35
+ ```
36
+ Trả về structured data (conversation timeline, tool executions, summary).
37
+
38
+ ## Cách sử dụng
39
+
40
+ ```javascript
41
+ // Sau khi có session_id từ /api/health-check
42
+ const sessionId = "abc-123-def";
43
+
44
+ // Generate full report
45
+ const response = await fetch(`/api/reports/${sessionId}?type=full`);
46
+ const { report } = await response.json();
47
+
48
+ // Hiển thị markdown
49
+ console.log(report.report_markdown);
50
+
51
+ // Hoặc parse structured data
52
+ const { conversation_timeline, tool_executions, summary } = report.report_content;
53
+ ```
54
+
55
+ ## Lưu ý
56
+ - Report được cache, gọi lại sẽ trả về cached version
57
+ - `type=full`: Báo cáo đầy đủ (default)
58
+ - `type=summary`: Chỉ tóm tắt
59
+ - `type=tools_only`: Chỉ tool executions
60
+
src/agent/agent-executor.ts CHANGED
@@ -369,6 +369,8 @@ Ví dụ format markdown NGẮN GỌN:
369
  logger.info(`[AGENT] Calling MCP RAG - searchGuidelines...`);
370
  const guidelines = await this.ragService.searchGuidelines(guidelineInput);
371
  logger.info(`[AGENT] Retrieved ${guidelines.length} guideline snippets from RAG`);
 
 
372
 
373
  // Step 4: Use LLM to synthesize final response
374
  logger.info('Step 4: Synthesizing final response with LLM...');
@@ -384,6 +386,9 @@ Ví dụ format markdown NGẮN GỌN:
384
  guidelines,
385
  conversationContext
386
  );
 
 
 
387
 
388
  // Step 5: Find best matching hospital if emergency/urgent and location provided
389
  // This tool is called LAST in the agent workflow
@@ -394,6 +399,7 @@ Ví dụ format markdown NGẮN GỌN:
394
 
395
  if ((triageResult.triage === 'emergency' || triageResult.triage === 'urgent') && location) {
396
  logger.info(`[AGENT] Step 5: Finding best matching hospital (emergency/urgent case)${condition ? ` for condition: ${condition}` : ''}...`);
 
397
  try {
398
  const bestHospital = await this.mapsService.findBestMatchingHospital(
399
  location,
@@ -402,20 +408,24 @@ Ví dụ format markdown NGẮN GỌN:
402
  );
403
  if (bestHospital) {
404
  logger.info(`[AGENT] Found best matching hospital: ${bestHospital.name} (${bestHospital.distance_km}km away${bestHospital.specialty_score ? `, specialty match: ${bestHospital.specialty_score.toFixed(2)}` : ''})`);
 
405
  return {
406
  ...finalResult,
407
  nearest_clinic: bestHospital
408
  };
409
  } else {
410
  logger.warn('[AGENT] No hospital found nearby');
 
411
  }
412
  } catch (error) {
413
  logger.error({ error }, '[AGENT] Failed to find best matching hospital');
 
414
  // Continue without hospital info
415
  }
416
  } else if (location && this.shouldSuggestHospital(userText)) {
417
  // Also suggest hospital if user explicitly requests it
418
  logger.info(`[AGENT] Step 5: Finding best matching hospital (user requested)${condition ? ` for condition: ${condition}` : ''}...`);
 
419
  try {
420
  const bestHospital = await this.mapsService.findBestMatchingHospital(
421
  location,
@@ -424,6 +434,7 @@ Ví dụ format markdown NGẮN GỌN:
424
  );
425
  if (bestHospital) {
426
  logger.info(`[AGENT] Found best matching hospital: ${bestHospital.name} (${bestHospital.distance_km}km away${bestHospital.specialty_score ? `, specialty match: ${bestHospital.specialty_score.toFixed(2)}` : ''})`);
 
427
  return {
428
  ...finalResult,
429
  nearest_clinic: bestHospital
@@ -431,6 +442,13 @@ Ví dụ format markdown NGẮN GỌN:
431
  }
432
  } catch (error) {
433
  logger.error({ error }, '[AGENT] Failed to find best matching hospital');
 
 
 
 
 
 
 
434
  }
435
  }
436
 
@@ -500,6 +518,9 @@ Ví dụ format markdown NGẮN GỌN:
500
  guidelines,
501
  conversationContext
502
  );
 
 
 
503
 
504
  // Step 4: Find best matching hospital if emergency/urgent and location provided
505
  // This tool is called LAST in the agent workflow
 
369
  logger.info(`[AGENT] Calling MCP RAG - searchGuidelines...`);
370
  const guidelines = await this.ragService.searchGuidelines(guidelineInput);
371
  logger.info(`[AGENT] Retrieved ${guidelines.length} guideline snippets from RAG`);
372
+ // Store guidelines count for report generation
373
+ (guidelineInput as any).guidelines_count = guidelines.length;
374
 
375
  // Step 4: Use LLM to synthesize final response
376
  logger.info('Step 4: Synthesizing final response with LLM...');
 
386
  guidelines,
387
  conversationContext
388
  );
389
+
390
+ // Attach guidelines count to result for report generation
391
+ (finalResult as any).guidelines_count = guidelines.length;
392
 
393
  // Step 5: Find best matching hospital if emergency/urgent and location provided
394
  // This tool is called LAST in the agent workflow
 
399
 
400
  if ((triageResult.triage === 'emergency' || triageResult.triage === 'urgent') && location) {
401
  logger.info(`[AGENT] Step 5: Finding best matching hospital (emergency/urgent case)${condition ? ` for condition: ${condition}` : ''}...`);
402
+ logger.info('[REPORT] Hospital tool (MCP) will be executed for emergency/urgent case');
403
  try {
404
  const bestHospital = await this.mapsService.findBestMatchingHospital(
405
  location,
 
408
  );
409
  if (bestHospital) {
410
  logger.info(`[AGENT] Found best matching hospital: ${bestHospital.name} (${bestHospital.distance_km}km away${bestHospital.specialty_score ? `, specialty match: ${bestHospital.specialty_score.toFixed(2)}` : ''})`);
411
+ logger.info(`[REPORT] ✓ Hospital tool (MCP) executed successfully: ${bestHospital.name}`);
412
  return {
413
  ...finalResult,
414
  nearest_clinic: bestHospital
415
  };
416
  } else {
417
  logger.warn('[AGENT] No hospital found nearby');
418
+ logger.info('[REPORT] Hospital tool (MCP) executed but no hospital found');
419
  }
420
  } catch (error) {
421
  logger.error({ error }, '[AGENT] Failed to find best matching hospital');
422
+ logger.error('[REPORT] Hospital tool (MCP) execution failed');
423
  // Continue without hospital info
424
  }
425
  } else if (location && this.shouldSuggestHospital(userText)) {
426
  // Also suggest hospital if user explicitly requests it
427
  logger.info(`[AGENT] Step 5: Finding best matching hospital (user requested)${condition ? ` for condition: ${condition}` : ''}...`);
428
+ logger.info('[REPORT] Hospital tool (MCP) will be executed (user explicitly requested)');
429
  try {
430
  const bestHospital = await this.mapsService.findBestMatchingHospital(
431
  location,
 
434
  );
435
  if (bestHospital) {
436
  logger.info(`[AGENT] Found best matching hospital: ${bestHospital.name} (${bestHospital.distance_km}km away${bestHospital.specialty_score ? `, specialty match: ${bestHospital.specialty_score.toFixed(2)}` : ''})`);
437
+ logger.info(`[REPORT] ✓ Hospital tool (MCP) executed successfully: ${bestHospital.name}`);
438
  return {
439
  ...finalResult,
440
  nearest_clinic: bestHospital
 
442
  }
443
  } catch (error) {
444
  logger.error({ error }, '[AGENT] Failed to find best matching hospital');
445
+ logger.error('[REPORT] Hospital tool (MCP) execution failed');
446
+ }
447
+ } else {
448
+ if (location) {
449
+ logger.info(`[REPORT] Hospital tool (MCP) skipped: triage_level=${triageResult.triage} (only called for emergency/urgent or explicit request)`);
450
+ } else {
451
+ logger.info('[REPORT] Hospital tool (MCP) skipped: no location provided');
452
  }
453
  }
454
 
 
518
  guidelines,
519
  conversationContext
520
  );
521
+
522
+ // Attach guidelines count to result for report generation
523
+ (finalResult as any).guidelines_count = guidelines.length;
524
 
525
  // Step 4: Find best matching hospital if emergency/urgent and location provided
526
  // This tool is called LAST in the agent workflow
src/routes/triage.route.ts CHANGED
@@ -260,18 +260,27 @@ export async function triageRoutes(
260
  // Continue even if saving fails
261
  }
262
 
263
- // Track tool executions (non-blocking)
264
  try {
 
 
265
  // Track CV execution if applicable
266
- await ToolTrackingHelper.trackCVExecution(
267
- toolTracker,
268
- activeSessionId,
269
- userMessage.id,
270
- triageResult,
271
- Math.floor(totalExecutionTime * 0.3) // Estimate 30% of time for CV
272
- );
 
 
 
 
 
 
273
 
274
  // Track Triage Rules execution
 
275
  await ToolTrackingHelper.trackTriageRulesExecution(
276
  toolTracker,
277
  activeSessionId,
@@ -280,9 +289,11 @@ export async function triageRoutes(
280
  normalizedText || 'Image analysis',
281
  Math.floor(totalExecutionTime * 0.2) // Estimate 20% of time
282
  );
 
283
 
284
- // Track RAG execution (estimate guidelines count from triage result)
285
- const guidelinesCount = (triageResult as any).guidelines_count || 3; // Default estimate
 
286
  await ToolTrackingHelper.trackRAGExecution(
287
  toolTracker,
288
  activeSessionId,
@@ -292,10 +303,12 @@ export async function triageRoutes(
292
  Math.floor(totalExecutionTime * 0.3), // Estimate 30% of time
293
  guidelinesCount
294
  );
 
295
 
296
- // Track Maps execution if hospital was found
297
  const nearestClinic = (triageResult as any).nearest_clinic;
298
  if (nearestClinic) {
 
299
  const condition = triageResult.suspected_conditions?.[0]?.name;
300
  await ToolTrackingHelper.trackMapsExecution(
301
  toolTracker,
@@ -305,9 +318,18 @@ export async function triageRoutes(
305
  condition,
306
  Math.floor(totalExecutionTime * 0.2) // Estimate 20% of time
307
  );
 
 
 
 
 
 
 
308
  }
 
 
309
  } catch (error) {
310
- logger.error({ error }, 'Failed to track tool executions');
311
  // Continue even if tracking fails
312
  }
313
 
 
260
  // Continue even if saving fails
261
  }
262
 
263
+ // Track tool executions for Report Generation (non-blocking)
264
  try {
265
+ logger.info('[REPORT] Starting tool execution tracking for report generation...');
266
+
267
  // Track CV execution if applicable
268
+ if (triageResult.cv_findings.model_used !== 'none') {
269
+ logger.info('[REPORT] Tracking CV tool execution...');
270
+ await ToolTrackingHelper.trackCVExecution(
271
+ toolTracker,
272
+ activeSessionId,
273
+ userMessage.id,
274
+ triageResult,
275
+ Math.floor(totalExecutionTime * 0.3) // Estimate 30% of time for CV
276
+ );
277
+ logger.info(`[REPORT] ✓ CV tool tracked: ${triageResult.cv_findings.model_used}`);
278
+ } else {
279
+ logger.info('[REPORT] CV tool not executed (no image or model_used=none)');
280
+ }
281
 
282
  // Track Triage Rules execution
283
+ logger.info('[REPORT] Tracking Triage Rules execution...');
284
  await ToolTrackingHelper.trackTriageRulesExecution(
285
  toolTracker,
286
  activeSessionId,
 
289
  normalizedText || 'Image analysis',
290
  Math.floor(totalExecutionTime * 0.2) // Estimate 20% of time
291
  );
292
+ logger.info(`[REPORT] ✓ Triage Rules tracked: level=${triageResult.triage_level}`);
293
 
294
+ // Track RAG execution - extract actual guidelines count from agent result
295
+ const guidelinesCount = (triageResult as any).guidelines_count || 3; // Captured from agent execution
296
+ logger.info('[REPORT] Tracking RAG/Guidelines execution...');
297
  await ToolTrackingHelper.trackRAGExecution(
298
  toolTracker,
299
  activeSessionId,
 
303
  Math.floor(totalExecutionTime * 0.3), // Estimate 30% of time
304
  guidelinesCount
305
  );
306
+ logger.info(`[REPORT] ✓ RAG tool tracked: ${guidelinesCount} guidelines retrieved`);
307
 
308
+ // Track Maps/Hospital execution if hospital was found
309
  const nearestClinic = (triageResult as any).nearest_clinic;
310
  if (nearestClinic) {
311
+ logger.info('[REPORT] Tracking Hospital/Maps tool execution...');
312
  const condition = triageResult.suspected_conditions?.[0]?.name;
313
  await ToolTrackingHelper.trackMapsExecution(
314
  toolTracker,
 
318
  condition,
319
  Math.floor(totalExecutionTime * 0.2) // Estimate 20% of time
320
  );
321
+ logger.info(`[REPORT] ✓ Hospital tool tracked: ${nearestClinic.name} (${nearestClinic.distance_km}km)`);
322
+ } else {
323
+ if (location) {
324
+ logger.info(`[REPORT] Hospital tool not executed: triage_level=${triageResult.triage_level} (only called for emergency/urgent or explicit request)`);
325
+ } else {
326
+ logger.info('[REPORT] Hospital tool not executed: no location provided');
327
+ }
328
  }
329
+
330
+ logger.info('[REPORT] ✓ All tool executions tracked successfully for report generation');
331
  } catch (error) {
332
+ logger.error({ error }, '[REPORT] Failed to track tool executions');
333
  // Continue even if tracking fails
334
  }
335
 
src/services/tool-execution-tracker.service.ts CHANGED
@@ -64,7 +64,12 @@ export class ToolExecutionTrackerService {
64
  logger.error({ error }, 'Failed to track tool execution');
65
  // Don't throw - tracking failure shouldn't break the workflow
66
  } else {
67
- logger.debug(`Tracked tool execution: ${execution.tool_name} (order: ${execution.execution_order})`);
 
 
 
 
 
68
  }
69
  } catch (error) {
70
  logger.error({ error }, 'Error tracking tool execution');
 
64
  logger.error({ error }, 'Failed to track tool execution');
65
  // Don't throw - tracking failure shouldn't break the workflow
66
  } else {
67
+ logger.info(`[REPORT] Tool execution saved to database: ${execution.tool_display_name} (${execution.tool_name}, order: ${execution.execution_order}, time: ${execution.execution_time_ms}ms)`);
68
+ logger.debug(`[REPORT] Tool execution data: ${JSON.stringify({
69
+ tool: execution.tool_name,
70
+ input: Object.keys(execution.input_data || {}),
71
+ output_keys: Object.keys(execution.output_data || {})
72
+ })}`);
73
  }
74
  } catch (error) {
75
  logger.error({ error }, 'Error tracking tool execution');