diff --git a/packages/services/conversation-service/src/infrastructure/agents/tools/coordinator-tools.ts b/packages/services/conversation-service/src/infrastructure/agents/tools/coordinator-tools.ts index d32569f..1d7f491 100644 --- a/packages/services/conversation-service/src/infrastructure/agents/tools/coordinator-tools.ts +++ b/packages/services/conversation-service/src/infrastructure/agents/tools/coordinator-tools.ts @@ -386,6 +386,19 @@ export const DIRECT_TOOLS: ToolDefinition[] = [ }, isConcurrencySafe: true, // 只读 }, + { + name: 'cancel_order', + description: + '取消未支付的订单。仅限未支付状态可取消。用户明确要求取消时使用。', + input_schema: { + type: 'object', + properties: { + orderId: { type: 'string', description: '要取消的订单 ID' }, + }, + required: ['orderId'], + }, + isConcurrencySafe: false, // 写操作 + }, ]; // ============================================================ diff --git a/packages/services/conversation-service/src/infrastructure/agents/tools/tool-execution-queue.ts b/packages/services/conversation-service/src/infrastructure/agents/tools/tool-execution-queue.ts index b64ef33..47afee6 100644 --- a/packages/services/conversation-service/src/infrastructure/agents/tools/tool-execution-queue.ts +++ b/packages/services/conversation-service/src/infrastructure/agents/tools/tool-execution-queue.ts @@ -276,4 +276,5 @@ export const TOOL_CONCURRENCY_MAP: Record = { save_user_memory: false, // 写操作 generate_payment: false, // 创建支付订单 collect_assessment_info: false, // 写操作 + cancel_order: false, // 取消订单 }; diff --git a/packages/services/conversation-service/src/infrastructure/claude/tools/immigration-tools.service.ts b/packages/services/conversation-service/src/infrastructure/claude/tools/immigration-tools.service.ts index e175674..d489fd9 100644 --- a/packages/services/conversation-service/src/infrastructure/claude/tools/immigration-tools.service.ts +++ b/packages/services/conversation-service/src/infrastructure/claude/tools/immigration-tools.service.ts @@ -154,6 +154,20 @@ export class ImmigrationToolsService { properties: {}, }, }, + { + name: 'cancel_order', + description: '取消未支付的订单。仅限状态为待支付的订单可以取消。当用户明确表示要取消订单时使用。', + input_schema: { + type: 'object', + properties: { + orderId: { + type: 'string', + description: '要取消的订单ID', + }, + }, + required: ['orderId'], + }, + }, { name: 'save_user_memory', description: '保存用户的重要信息到长期记忆,以便后续对话中记住用户情况', @@ -306,6 +320,9 @@ export class ImmigrationToolsService { case 'query_order_history': return this.queryOrderHistory(context); + case 'cancel_order': + return this.cancelOrder(input); + case 'save_user_memory': return this.saveUserMemory(input, context); @@ -615,6 +632,36 @@ export class ImmigrationToolsService { }; } + /** + * Cancel order — 取消未支付的订单 + */ + private async cancelOrder( + input: Record, + ): Promise { + const { orderId } = input as { orderId: string }; + + console.log(`[Tool:cancel_order] Order: ${orderId}`); + + if (!this.paymentClient) { + return { success: false, error: '支付服务暂不可用' }; + } + + const result = await this.paymentClient.cancelOrder(orderId); + if (!result) { + return { + success: false, + error: '取消订单失败。只有未支付的订单才能取消,请确认订单状态。', + }; + } + + return { + success: true, + orderId: result.orderId, + status: result.status, + message: '订单已成功取消', + }; + } + /** * Save user memory - 调用 knowledge-service Memory API */ diff --git a/packages/services/conversation-service/src/infrastructure/payment/payment-client.service.ts b/packages/services/conversation-service/src/infrastructure/payment/payment-client.service.ts index 2ae934a..2747a57 100644 --- a/packages/services/conversation-service/src/infrastructure/payment/payment-client.service.ts +++ b/packages/services/conversation-service/src/infrastructure/payment/payment-client.service.ts @@ -223,4 +223,57 @@ export class PaymentClientService implements OnModuleInit { return []; } } + + /** + * 获取单个订单详情 + */ + async getOrderDetail(orderId: string): Promise { + try { + const response = await fetch(`${this.baseUrl}/orders/${orderId}`); + + if (!response.ok) { + console.error( + `[PaymentClient] getOrderDetail failed: ${response.status}`, + ); + return null; + } + + const data = (await response.json()) as ApiResponse; + return data.success ? data.data : null; + } catch (error) { + console.error('[PaymentClient] getOrderDetail error:', error); + return null; + } + } + + /** + * 取消订单(仅限未支付的订单) + */ + async cancelOrder( + orderId: string, + ): Promise<{ orderId: string; status: string } | null> { + try { + const response = await fetch( + `${this.baseUrl}/orders/${orderId}/cancel`, + { method: 'POST' }, + ); + + if (!response.ok) { + const errText = await response.text(); + console.error( + `[PaymentClient] cancelOrder failed: ${response.status} ${errText}`, + ); + return null; + } + + const data = (await response.json()) as ApiResponse<{ + orderId: string; + status: string; + }>; + return data.success ? data.data : null; + } catch (error) { + console.error('[PaymentClient] cancelOrder error:', error); + return null; + } + } } diff --git a/packages/web-client/src/features/chat/presentation/components/MessageBubble.tsx b/packages/web-client/src/features/chat/presentation/components/MessageBubble.tsx index 458685e..1887859 100644 --- a/packages/web-client/src/features/chat/presentation/components/MessageBubble.tsx +++ b/packages/web-client/src/features/chat/presentation/components/MessageBubble.tsx @@ -397,5 +397,35 @@ function ToolCallResult({ } } + if (toolCall.name === 'cancel_order') { + const result = toolCall.result as { + success?: boolean; + orderId?: string; + message?: string; + error?: string; + }; + + return ( +
+
+ {result.success ? ( + + ) : ( + + )} + + {result.success ? result.message : result.error} + +
+ {result.orderId && ( +

订单号: {result.orderId}

+ )} +
+ ); + } + return null; }