feat: ship deterministic parser and lifecycle release

This commit is contained in:
inman committed 2026-08-28 17:13:58 +08:00
1 parent 208c434b31
commit 7b5d855b09
176 files changed
+20248 -1362

No files matched your search

+17 -38
View File
@@ -1,52 +1,31 @@
import {
BUSINESS_DIRECTIVE_PREFIXES,
firstNonEmptyLine,
normalizeDirectiveText,
resolveBusinessRoute
} from './business-routes.js';
/**
* Business instruction prefixes that start an independent task.
*
* A message sent while another task is waiting for input is normally a
* continuation. When the user starts the first non-empty line with one of
* these business instructions, however, it is a new request and must get a
* new task/session instead of inheriting the previous parser context.
* continuation. A unique registered directive anywhere in a structured block
* is a new request and must get a new task/session instead of inheriting the
* previous parser context. A field signature may select the parser mode for a
* new task, but never changes continuation semantics by itself.
*/
export const BUSINESS_DIRECTIVE_PREFIXES = Object.freeze([
'独立团单个下单',
'独立团批量下单',
'散拼团新增计划',
'散拼团单个新增子单',
'散拼团拼单',
'导入独立团名单',
'导入散拼子单名单',
'安排导游',
'安排用车',
'安排酒店',
'安排大交通',
'安排其他/备案',
'安排其他',
'修改散拼母团计划收客数',
'散拼母团信息修改',
'追加散拼子单订房说明',
'散拼子单信息修改',
'独立团信息修改',
'安排变更',
'取消订单',
'恢复订单',
'导出团队文件'
] as const);
function normalizedFirstLine(message: string): string {
const firstLine = String(message || '')
.replace(/^\uFEFF/, '')
.split(/\r?\n/)
.map((line) => line.trim())
.find(Boolean) || '';
// NFKC handles full-width punctuation/letters; removing whitespace lets a
// copied template such as “安排 用车” follow the same route as “安排用车”.
return firstLine.normalize('NFKC').replace(/[\s\u3000]+/g, '');
return normalizeDirectiveText(firstNonEmptyLine(message));
}
export function detectBusinessDirective(message: string): string | null {
const line = normalizedFirstLine(message);
if (!line) return null;
return BUSINESS_DIRECTIVE_PREFIXES.find((prefix) => line.startsWith(prefix)) || null;
const exactOrFuzzy = resolveBusinessRoute(message);
if (exactOrFuzzy.routeId && exactOrFuzzy.match !== 'signature') {
return exactOrFuzzy.matchedDirective || exactOrFuzzy.route?.directive || null;
}
return BUSINESS_DIRECTIVE_PREFIXES.find((prefix) => line.startsWith(normalizeDirectiveText(prefix))) || null;
}
export function isNewDirectiveMessage(message: string): boolean {