指令问题修复
This commit is contained in:
@@ -79,8 +79,8 @@ export function effectiveParserModeForRoute(route: BusinessRouteDefinition, conf
|
||||
return route.parserPolicy === 'program_only' ? 'program' : 'ai';
|
||||
}
|
||||
|
||||
const PROGRAM_VERSION = 'ltjt-program-parser-v1.0.12';
|
||||
export const BUSINESS_INPUT_CONTRACT_VERSION = 'business-input-templates-0.5.135';
|
||||
const PROGRAM_VERSION = 'ltjt-program-parser-v1.0.13';
|
||||
export const BUSINESS_INPUT_CONTRACT_VERSION = 'business-input-templates-0.5.136';
|
||||
|
||||
const lookupFields = ({ customerRequired = true } = {}): ProgramFieldDefinition[] => [
|
||||
{ key: 'order_no', label: '单号', aliases: ['团号', '订单号'], kind: 'text' },
|
||||
|
||||
@@ -387,14 +387,14 @@ const ROOM_CODES = new Map<string, string>([
|
||||
['SGL', 'SGL'], ['单', 'SGL'], ['单间', 'SGL'], ['单人间', 'SGL'],
|
||||
['TWN', 'TWN'], ['标', 'TWN'], ['标间', 'TWN'], ['双标间', 'TWN'],
|
||||
['TRP', 'TRP'], ['三', 'TRP'], ['三人间', 'TRP'],
|
||||
['DBL', 'DBL'], ['双', 'DBL'], ['双人间', 'DBL'], ['大床', 'DBL'], ['大床房', 'DBL']
|
||||
['DBL', 'DBL'], ['双', 'DBL'], ['双人间', 'DBL'], ['大床', 'DBL'], ['大床房', 'DBL'], ['大', 'DBL']
|
||||
]);
|
||||
|
||||
function parseRoomCounts(rawValue: string): FieldParseResult {
|
||||
const value = compactText(rawValue).replace(/\s+/gu, '');
|
||||
const result: JsonRecord = {};
|
||||
const consumed: string[] = [];
|
||||
const pattern = /(\d+)\s*(SGL|TWN|TRP|DBL|单人间|单间|单|双标间|标间|标|三人间|三|双人间|大床房|大床|双)/giu;
|
||||
const pattern = /(\d+)\s*(SGL|TWN|TRP|DBL|单人间|单间|单|双标间|标间|标|三人间|三|双人间|大床房|大床|大|双)/giu;
|
||||
for (const match of value.matchAll(pattern)) {
|
||||
const code = ROOM_CODES.get(match[2].toUpperCase()) || ROOM_CODES.get(match[2]);
|
||||
if (!code) continue;
|
||||
@@ -475,7 +475,7 @@ function splitControlledClauses(rawValue: string): string[] {
|
||||
}
|
||||
|
||||
function controlledAssignment(clause: string): { target: string; value: string } | null {
|
||||
const match = clause.match(/^(.+?)(?:调整为|变更为|修改为|改为|设为|=|:|:)\s*(.+)$/u);
|
||||
const match = clause.match(/^(.+?)(?:调整为|变更为|修改为|更改为|改为|设为|=|:|:)\s*(.+)$/u);
|
||||
const target = compactText(match?.[1] || '').replace(/\s+/gu, '');
|
||||
const value = compactText(match?.[2] || '');
|
||||
return target && value ? { target, value } : null;
|
||||
@@ -504,7 +504,7 @@ function parseIndependentUpdates(rawValue: string, context: DateContext, nextOcc
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (/^(?:用房数量|房型数量|用房|房间)$/u.test(target)) {
|
||||
if (/^(?:用房数量|房型数量|房间数|用房|房间)$/u.test(target)) {
|
||||
const rooms = parseRoomCounts(value);
|
||||
if (!rooms.ok) return { ok: false, code: 'program_invalid_value', message: rooms.message, field: 'update_targets' };
|
||||
for (const [key, count] of Object.entries(rooms.value as JsonRecord)) {
|
||||
|
||||
@@ -189,7 +189,7 @@ test('versioned sanitized gold corpus replays deterministically', async () => {
|
||||
const corpus = JSON.parse(await readFile(
|
||||
new URL('../../samples/business-parser-gold-corpus.json', import.meta.url), 'utf8'
|
||||
));
|
||||
assert.equal(corpus.version, 'ltjt-program-parser-v1.0.12');
|
||||
assert.equal(corpus.version, 'ltjt-program-parser-v1.0.13');
|
||||
assert.ok(corpus.cases.length >= 28);
|
||||
for (const candidate of corpus.cases) {
|
||||
const parse = () => parseProgramInput({
|
||||
@@ -313,6 +313,31 @@ test('passenger TSV rejects duplicate leaders or a leader without both name and
|
||||
}
|
||||
});
|
||||
|
||||
test('independent room updates accept DBL shorthand without dropping other intentions', async () => {
|
||||
for (const target of [
|
||||
'房间数更改为 12 标+2 大', '用房数量改为12标+2大床',
|
||||
'房型数量修改为12TWN+2DBL', '房间调整为12标间+2大床房'
|
||||
]) {
|
||||
const result = await parseProgramInput({ rawText: `独立团信息修改\n预订客户:测试客户\n出发日期:2026-09-16\n目标修改:${target}`, receivedAt });
|
||||
assert.equal(result.status, 'agent_parse_passed', JSON.stringify(result));
|
||||
assert.deepEqual((result.operation as any).data.updates.actions, [
|
||||
{ target: 'rooms.TWN', operation: 'set', value: 12 },
|
||||
{ target: 'rooms.DBL', operation: 'set', value: 2 }
|
||||
]);
|
||||
}
|
||||
const combined = await parseProgramInput({ rawText: '独立团信息修改\n预订客户:测试客户\n出发日期:2026-09-16\n目标修改:房间数更改为12标+2大,成人更改为28', receivedAt });
|
||||
assert.equal(combined.status, 'agent_parse_passed');
|
||||
assert.equal((combined.operation as any).data.updates.actions[2].value, 28);
|
||||
for (const target of ['房间数更改为12', '房间数更改为12标+2大楼', '房间数更改为12标+2大+1DBL', '大床房数改为-1', '房间数更改为12标+2大;DBL改为3']) {
|
||||
const result = await parseProgramInput({ rawText: `独立团信息修改\n预订客户:测试客户\n出发日期:2026-09-16\n目标修改:${target}`, receivedAt });
|
||||
assert.notEqual(result.status, 'agent_parse_passed', target);
|
||||
assert.equal(result.operation, null);
|
||||
}
|
||||
const clear = await parseProgramInput({ rawText: '独立团信息修改\n预订客户:测试客户\n出发日期:2026-09-16\n目标修改:大床房数更改为0', receivedAt });
|
||||
assert.equal(clear.status, 'agent_parse_passed');
|
||||
assert.deepEqual((clear.operation as any).data.updates.actions, [{ target: 'rooms.DBL', operation: 'set', value: 0 }]);
|
||||
});
|
||||
|
||||
test('independent headcount distributions keep occupied and non-occupied children distinct', async () => {
|
||||
const parseHeadcount = (value: string) => parseProgramInput({
|
||||
rawText: routeCases[14].input.replace(
|
||||
|
||||
Reference in New Issue
Block a user