实现酒店上下文单酒店收口
This commit is contained in:
@@ -4,7 +4,7 @@ import cn.nianxx.thhotel.integrations.ai.superagent.common.request.SuperAgentTas
|
||||
import cn.nianxx.thhotel.integrations.ai.superagent.service.SuperAgentTaskResultSecurityService;
|
||||
import cn.nianxx.thhotel.integrations.ai.superagent.service.impl.SuperAgentTaskResultException;
|
||||
import cn.nianxx.thhotel.integrations.ai.superagent.service.impl.SuperAgentTaskResultProperties;
|
||||
import cn.nianxx.thhotel.integrations.messaging.agentbus.adapter.AgentBusProperties;
|
||||
import cn.nianxx.thhotel.platform.hotel.service.HotelContextService;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.result.SuperAgentTaskResultResponse;
|
||||
import cn.nianxx.thhotel.workflows.reservation.service.ReservationAiTaskIntakeService;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -29,7 +29,7 @@ public class SuperAgentTaskResultController {
|
||||
|
||||
private final SuperAgentTaskResultSecurityService securityService;
|
||||
private final SuperAgentTaskResultProperties properties;
|
||||
private final AgentBusProperties agentBusProperties;
|
||||
private final HotelContextService hotelContextService;
|
||||
private final ReservationAiTaskIntakeService intakeService;
|
||||
|
||||
/**
|
||||
@@ -38,11 +38,11 @@ public class SuperAgentTaskResultController {
|
||||
public SuperAgentTaskResultController(
|
||||
SuperAgentTaskResultSecurityService securityService,
|
||||
SuperAgentTaskResultProperties properties,
|
||||
AgentBusProperties agentBusProperties,
|
||||
HotelContextService hotelContextService,
|
||||
ReservationAiTaskIntakeService intakeService) {
|
||||
this.securityService = securityService;
|
||||
this.properties = properties;
|
||||
this.agentBusProperties = agentBusProperties;
|
||||
this.hotelContextService = hotelContextService;
|
||||
this.intakeService = intakeService;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class SuperAgentTaskResultController {
|
||||
requestBody,
|
||||
clientId,
|
||||
requestId,
|
||||
agentBusProperties.getCapture().getDefaultHotelId());
|
||||
hotelContextService.resolveSystemHotelId());
|
||||
HttpStatus status = response.idempotentReplay() ? HttpStatus.OK : HttpStatus.CREATED;
|
||||
return ResponseEntity.status(status).body(response);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package cn.nianxx.thhotel.integrations.ai.superagent.control;
|
||||
|
||||
import cn.nianxx.thhotel.integrations.ai.superagent.common.result.SuperAgentTaskResultErrorResponse;
|
||||
import cn.nianxx.thhotel.integrations.ai.superagent.service.impl.SuperAgentTaskResultException;
|
||||
import cn.nianxx.thhotel.platform.hotel.service.HotelContextException;
|
||||
import cn.nianxx.thhotel.workflows.reservation.service.impl.ReservationAiTaskIntakeException;
|
||||
import java.util.List;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -34,6 +35,16 @@ public class SuperAgentTaskResultControllerAdvice {
|
||||
.body(error(exception.getErrorCode(), exception.getMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理系统酒店缺失、多 ACTIVE 酒店或酒店访问受限等上下文异常。
|
||||
*/
|
||||
@ExceptionHandler(HotelContextException.class)
|
||||
public ResponseEntity<SuperAgentTaskResultErrorResponse> handleHotelContextException(
|
||||
HotelContextException exception) {
|
||||
return ResponseEntity.status(exception.getStatus())
|
||||
.body(error(exception.getErrorCode(), exception.getMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建统一错误响应,第一版不回显 request_id,避免异常路径暴露未经校验的外部输入。
|
||||
*/
|
||||
|
||||
@@ -8,6 +8,8 @@ import cn.nianxx.thhotel.integrations.mcp.superagent.common.result.SuperAgentMcp
|
||||
import cn.nianxx.thhotel.integrations.mcp.superagent.common.result.SuperAgentMcpToolDefinition;
|
||||
import cn.nianxx.thhotel.integrations.mcp.superagent.common.result.SuperAgentMcpToolsListResult;
|
||||
import cn.nianxx.thhotel.integrations.mcp.superagent.service.SuperAgentMcpService;
|
||||
import cn.nianxx.thhotel.platform.hotel.service.HotelContextService;
|
||||
import cn.nianxx.thhotel.platform.hotel.service.HotelContextException;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.request.ReservationAiCaseContextQueryRequest;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.request.ReservationAiObjectDetailQueryRequest;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.request.ReservationMessageConversationQueryRequest;
|
||||
@@ -48,6 +50,7 @@ public class SuperAgentMcpServiceImpl implements SuperAgentMcpService {
|
||||
private final ReservationAiTaskIntakeService intakeService;
|
||||
private final SuperAgentMcpProperties properties;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final HotelContextService hotelContextService;
|
||||
|
||||
/**
|
||||
* 注入已有业务服务和 JSON 工具,MCP 层不直接访问 Mapper 或数据库。
|
||||
@@ -56,11 +59,13 @@ public class SuperAgentMcpServiceImpl implements SuperAgentMcpService {
|
||||
ReservationAiQueryService aiQueryService,
|
||||
ReservationAiTaskIntakeService intakeService,
|
||||
SuperAgentMcpProperties properties,
|
||||
ObjectMapper objectMapper) {
|
||||
ObjectMapper objectMapper,
|
||||
HotelContextService hotelContextService) {
|
||||
this.aiQueryService = aiQueryService;
|
||||
this.intakeService = intakeService;
|
||||
this.properties = properties;
|
||||
this.objectMapper = objectMapper;
|
||||
this.hotelContextService = hotelContextService;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,6 +159,13 @@ public class SuperAgentMcpServiceImpl implements SuperAgentMcpService {
|
||||
exception.getErrorCode(),
|
||||
exception.getMessage(),
|
||||
Map.of("http_status", exception.getStatus().value())));
|
||||
} catch (HotelContextException exception) {
|
||||
return SuperAgentMcpToolCallResult.error(
|
||||
"TH Hotel 酒店上下文解析失败:" + exception.getMessage(),
|
||||
errorStructuredContent(
|
||||
exception.getErrorCode(),
|
||||
exception.getMessage(),
|
||||
Map.of("http_status", exception.getStatus().value())));
|
||||
} catch (IllegalArgumentException exception) {
|
||||
return SuperAgentMcpToolCallResult.error(
|
||||
"MCP 工具参数不合法。",
|
||||
@@ -238,7 +250,11 @@ public class SuperAgentMcpServiceImpl implements SuperAgentMcpService {
|
||||
Map.of("tool", TOOL_SUBMIT_TASK_RESULTS)));
|
||||
}
|
||||
String rawBody = objectMapper.writeValueAsString(arguments);
|
||||
SuperAgentTaskResultResponse response = intakeService.accept(rawBody, MCP_CLIENT_ID, null);
|
||||
SuperAgentTaskResultResponse response = intakeService.accept(
|
||||
rawBody,
|
||||
MCP_CLIENT_ID,
|
||||
null,
|
||||
hotelContextService.resolveSystemHotelId());
|
||||
return SuperAgentMcpToolCallResult.success(TOOL_SUBMIT_TASK_RESULTS + " 调用成功。", response);
|
||||
}
|
||||
|
||||
@@ -311,37 +327,37 @@ public class SuperAgentMcpServiceImpl implements SuperAgentMcpService {
|
||||
|
||||
private Map<String, Object> caseContextSchema() {
|
||||
Map<String, Object> propertiesMap = new LinkedHashMap<>();
|
||||
propertiesMap.put("hotel_id", stringField("酒店上下文 ID"));
|
||||
propertiesMap.put("hotel_id", stringField("可选酒店上下文 ID;缺省由 TH Hotel 后端解析系统酒店"));
|
||||
propertiesMap.put("group_code", nullableStringField("Group / Allotment 查询 key"));
|
||||
propertiesMap.put("confirmation_number", nullableStringField("FIT confirmation number 查询 key"));
|
||||
propertiesMap.put("reservation_no", nullableStringField("OPERA reservation no"));
|
||||
propertiesMap.put("object_type_hint", nullableStringField("调用方推测的对象类型"));
|
||||
propertiesMap.put("target_key_source", nullableStringField("key 来源,例如 body_current"));
|
||||
propertiesMap.put("body_thread_used_only_as_evidence", Map.of("type", "boolean", "description", "历史线程 key 是否仅作为证据"));
|
||||
return objectSchema(propertiesMap, List.of("hotel_id"));
|
||||
return objectSchema(propertiesMap, List.of());
|
||||
}
|
||||
|
||||
private Map<String, Object> objectDetailSchema() {
|
||||
Map<String, Object> propertiesMap = new LinkedHashMap<>();
|
||||
propertiesMap.put("hotel_id", stringField("酒店上下文 ID"));
|
||||
propertiesMap.put("hotel_id", stringField("可选酒店上下文 ID;缺省由 TH Hotel 后端解析系统酒店"));
|
||||
propertiesMap.put("object_id", stringField("查询对象 ID,第一版支持 ORDER:{order_id}"));
|
||||
propertiesMap.put("object_type", nullableStringField("调用方对象类型提示"));
|
||||
return objectSchema(propertiesMap, List.of("hotel_id", "object_id"));
|
||||
return objectSchema(propertiesMap, List.of("object_id"));
|
||||
}
|
||||
|
||||
private Map<String, Object> conversationQuerySchema() {
|
||||
Map<String, Object> propertiesMap = new LinkedHashMap<>();
|
||||
propertiesMap.put("hotel_id", stringField("酒店上下文 ID"));
|
||||
propertiesMap.put("hotel_id", stringField("可选酒店上下文 ID;缺省由 TH Hotel 后端解析系统酒店"));
|
||||
propertiesMap.put("source_provider", nullableStringField("来源提供方,默认 AGENTBUS"));
|
||||
propertiesMap.put("source_channel", nullableStringField("来源渠道,默认 EMAIL"));
|
||||
propertiesMap.put("external_conversation_id", nullableStringField("外部邮件会话 ID"));
|
||||
propertiesMap.put("source_message_id", nullableStringField("外部来源消息 ID,可作为锚点反查会话"));
|
||||
return objectSchema(propertiesMap, List.of("hotel_id"));
|
||||
return objectSchema(propertiesMap, List.of());
|
||||
}
|
||||
|
||||
private Map<String, Object> submitTaskResultsSchema() {
|
||||
Map<String, Object> propertiesMap = new LinkedHashMap<>();
|
||||
propertiesMap.put("hotel_id", stringField("酒店上下文 ID"));
|
||||
propertiesMap.put("hotel_id", stringField("可选酒店上下文 ID;缺省由 TH Hotel 后端解析系统酒店"));
|
||||
propertiesMap.put("source_provider", nullableStringField("来源提供方,默认 AGENTBUS"));
|
||||
propertiesMap.put("source_channel", nullableStringField("来源渠道,默认 EMAIL"));
|
||||
propertiesMap.put("source_message_id", stringField("外部来源消息 ID,对应 AgentBus source.external_message_id"));
|
||||
@@ -353,7 +369,7 @@ public class SuperAgentMcpServiceImpl implements SuperAgentMcpService {
|
||||
"type", "array",
|
||||
"description", "AI 抽取警告",
|
||||
"items", Map.of("type", "object")));
|
||||
return objectSchema(propertiesMap, List.of("hotel_id", "source_message_id", "ai_task_results"));
|
||||
return objectSchema(propertiesMap, List.of("source_message_id", "ai_task_results"));
|
||||
}
|
||||
|
||||
private Map<String, Object> objectSchema(Map<String, Object> propertiesMap, List<String> required) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package cn.nianxx.thhotel.integrations.messaging.agentbus.adapter;
|
||||
import cn.nianxx.thhotel.platform.message.common.request.CaptureSourceMessageCommand;
|
||||
import cn.nianxx.thhotel.platform.message.common.result.SourceMessageCaptureResult;
|
||||
import cn.nianxx.thhotel.platform.message.service.SourceMessageCaptureService;
|
||||
import cn.nianxx.thhotel.platform.hotel.service.HotelContextService;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -26,6 +27,7 @@ public class AgentBusFrameProcessor {
|
||||
private final SourceMessageCaptureService captureService;
|
||||
private final AgentBusConnectionStatus status;
|
||||
private final AgentBusProperties properties;
|
||||
private final HotelContextService hotelContextService;
|
||||
|
||||
/**
|
||||
* 注入 AgentBus frame 处理依赖。外部协议转换与平台捕获服务通过稳定命令隔离。
|
||||
@@ -35,12 +37,14 @@ public class AgentBusFrameProcessor {
|
||||
AgentBusSourceMessageAdapter sourceMessageAdapter,
|
||||
SourceMessageCaptureService captureService,
|
||||
AgentBusConnectionStatus status,
|
||||
AgentBusProperties properties) {
|
||||
AgentBusProperties properties,
|
||||
HotelContextService hotelContextService) {
|
||||
this.objectMapper = objectMapper;
|
||||
this.sourceMessageAdapter = sourceMessageAdapter;
|
||||
this.captureService = captureService;
|
||||
this.status = status;
|
||||
this.properties = properties;
|
||||
this.hotelContextService = hotelContextService;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,8 +73,9 @@ public class AgentBusFrameProcessor {
|
||||
return AgentBusFrameProcessResult.ignored();
|
||||
}
|
||||
try {
|
||||
String hotelId = hotelContextService.resolveSystemHotelId();
|
||||
CaptureSourceMessageCommand command = sourceMessageAdapter.toCaptureCommand(
|
||||
properties.getCapture().getDefaultHotelId(),
|
||||
hotelId,
|
||||
frame);
|
||||
SourceMessageCaptureResult result = captureService.capture(command);
|
||||
status.markFrameCaptured();
|
||||
|
||||
@@ -123,8 +123,6 @@ public class AgentBusProperties {
|
||||
|
||||
/** 是否把业务 frame 写入 SourceMessage Inbox。 */
|
||||
private boolean enabled = true;
|
||||
/** AgentBus 未提供酒店上下文时使用的默认酒店 ID。 */
|
||||
private String defaultHotelId = "HOTEL-TEST";
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
@@ -133,13 +131,5 @@ public class AgentBusProperties {
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getDefaultHotelId() {
|
||||
return defaultHotelId;
|
||||
}
|
||||
|
||||
public void setDefaultHotelId(String defaultHotelId) {
|
||||
this.defaultHotelId = defaultHotelId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user