fix(tools): 修复 coordinator-tools 与 immigration-tools 之间的 input_schema 不一致
## 问题
全链路检查发现 coordinator-tools.ts(Claude 实际使用的工具定义)与
immigration-tools.service.ts(实际执行器)之间有 4 处 input_schema 不一致,
会导致 Claude 发送的参数无法被正确解析。
## 修复
### check_off_topic
- coordinator 发 `query`,handler 读 `question`
- Fix: handler 同时支持 `query` 和 `question` 两个字段名
### collect_assessment_info
- coordinator 发 `{ userId, field, value }`(单字段模式)
- handler 读 `{ category, age, education, ... }`(批量模式)
- Fix: handler 同时支持两种输入格式
### generate_payment
- coordinator 旧 schema: `{ userId, serviceType, amount, description }`
- handler 需要: `{ serviceType, category, paymentMethod }`
- Fix: 更新 coordinator schema 为 `{ serviceType, category, paymentMethod }`
- serviceType enum 改为 ASSESSMENT/CONSULTATION/DOCUMENT_REVIEW(匹配 payment-service)
- 添加 category enum 和 paymentMethod enum
- 移除 userId(从 context 获取)和 amount(由 payment-service 定价)
### save_user_memory
- coordinator 旧 schema 多余 `userId`(handler 用 context.userId)
- coordinator 发 `importance` 但 handler 不读
- handler 支持 `category` 但 coordinator 未定义
- Fix: coordinator schema 移除 userId,移除 importance,添加 category
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a3f2be078b
commit
9e9865acb0
|
|
@ -298,23 +298,24 @@ export const DIRECT_TOOLS: ToolDefinition[] = [
|
|||
name: 'save_user_memory',
|
||||
description:
|
||||
'直接保存用户信息到长期记忆。' +
|
||||
'用于保存关键信息,无需启动完整的记忆管理 Agent。',
|
||||
'用于保存关键信息,无需启动完整的记忆管理 Agent。' +
|
||||
'userId 不需要传,系统自动获取。',
|
||||
input_schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
userId: { type: 'string', description: '用户 ID' },
|
||||
memoryType: {
|
||||
type: 'string',
|
||||
enum: ['FACT', 'PREFERENCE', 'INTENT'],
|
||||
description: '记忆类型',
|
||||
description: '记忆类型:FACT-用户事实,PREFERENCE-偏好,INTENT-意图',
|
||||
},
|
||||
content: { type: 'string', description: '记忆内容' },
|
||||
importance: {
|
||||
type: 'number',
|
||||
description: '重要程度 1-10',
|
||||
content: { type: 'string', description: '要记住的内容' },
|
||||
category: {
|
||||
type: 'string',
|
||||
enum: ['QMAS', 'GEP', 'IANG', 'TTPS', 'CIES', 'TECHTAS'],
|
||||
description: '相关移民类别(可选)',
|
||||
},
|
||||
},
|
||||
required: ['userId', 'memoryType', 'content'],
|
||||
required: ['memoryType', 'content'],
|
||||
},
|
||||
isConcurrencySafe: false,
|
||||
},
|
||||
|
|
@ -346,20 +347,28 @@ export const DIRECT_TOOLS: ToolDefinition[] = [
|
|||
{
|
||||
name: 'generate_payment',
|
||||
description:
|
||||
'生成支付链接。仅在用户明确表示要付费或预约服务时使用。',
|
||||
'生成支付二维码。仅在用户明确表示要付费或预约服务时使用。' +
|
||||
'需要确认用户选择的服务类别和支付方式后调用。',
|
||||
input_schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
userId: { type: 'string', description: '用户 ID' },
|
||||
serviceType: {
|
||||
type: 'string',
|
||||
enum: ['assessment', 'consultation', 'full_service'],
|
||||
enum: ['ASSESSMENT', 'CONSULTATION', 'DOCUMENT_REVIEW'],
|
||||
description: '服务类型',
|
||||
},
|
||||
amount: { type: 'number', description: '金额(HKD)' },
|
||||
description: { type: 'string', description: '服务描述' },
|
||||
category: {
|
||||
type: 'string',
|
||||
enum: ['QMAS', 'GEP', 'IANG', 'TTPS', 'CIES', 'TECHTAS'],
|
||||
description: '移民类别',
|
||||
},
|
||||
paymentMethod: {
|
||||
type: 'string',
|
||||
enum: ['ALIPAY', 'WECHAT', 'CREDIT_CARD'],
|
||||
description: '支付方式(支付宝、微信、信用卡)',
|
||||
},
|
||||
},
|
||||
required: ['userId', 'serviceType'],
|
||||
required: ['serviceType', 'category', 'paymentMethod'],
|
||||
},
|
||||
isConcurrencySafe: false,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -427,7 +427,8 @@ export class ImmigrationToolsService {
|
|||
* Check if question is off-topic - 调用 knowledge-service API
|
||||
*/
|
||||
private async checkOffTopic(input: Record<string, unknown>): Promise<unknown> {
|
||||
const { question } = input as { question: string };
|
||||
// coordinator-tools.ts sends `query`, legacy getTools() sent `question`
|
||||
const question = (input.query as string) || (input.question as string) || '';
|
||||
|
||||
console.log(`[Tool:check_off_topic] Checking: "${question}"`);
|
||||
|
||||
|
|
@ -456,19 +457,22 @@ export class ImmigrationToolsService {
|
|||
input: Record<string, unknown>,
|
||||
context: ConversationContext,
|
||||
): Promise<unknown> {
|
||||
const info = input as {
|
||||
category: string;
|
||||
age?: number;
|
||||
education?: string;
|
||||
university?: string;
|
||||
yearsOfExperience?: number;
|
||||
currentJobTitle?: string;
|
||||
industry?: string;
|
||||
annualIncome?: number;
|
||||
hasHKEmployer?: boolean;
|
||||
};
|
||||
// coordinator-tools.ts sends { userId, field, value } (single-field mode)
|
||||
// Legacy getTools() sent { category, age, education, ... } (batch mode)
|
||||
// Support both formats
|
||||
let info: Record<string, unknown>;
|
||||
|
||||
console.log(`[Tool:collect_assessment_info] User ${context.userId} - Category: ${info.category}`);
|
||||
if (input.field && input.value) {
|
||||
// Single-field mode from coordinator-tools.ts
|
||||
info = { [input.field as string]: input.value };
|
||||
} else {
|
||||
// Batch mode from legacy getTools()
|
||||
const { userId: _userId, ...rest } = input;
|
||||
info = rest;
|
||||
}
|
||||
|
||||
const category = (info.category as string) || '';
|
||||
console.log(`[Tool:collect_assessment_info] User ${context.userId} - Fields: ${Object.keys(info).join(', ')}`);
|
||||
|
||||
// 保存收集到的信息到用户记忆
|
||||
const memoryContent = Object.entries(info)
|
||||
|
|
@ -482,7 +486,7 @@ export class ImmigrationToolsService {
|
|||
memoryType: 'FACT',
|
||||
content: `用户评估信息 - ${memoryContent}`,
|
||||
sourceConversationId: context.conversationId,
|
||||
relatedCategory: info.category,
|
||||
relatedCategory: category,
|
||||
importance: 80,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue