// @ts-nocheck import { inferTimetableQuery as sharedInfer, normalizeTimetableQuery as sharedNormalize } from './timetable-query.js'; import * as sessionContext from '../core/session-context.js'; export function inferTimetableQuery(text) { return sharedInfer(text); } export function normalizeTimetableQuery(raw) { return sharedNormalize(raw); } const DAY_TYPE_TO_QUERY = { WORKDAY: '工作日', WORK_DAY: '工作日', HOLIDAY: '节假日', WEEKEND: '周末', workday: '工作日', holiday: '节假日', }; function resolveTimetableQuery(args, userInput) { const aliases = ['fileName', 'name', 'timetableName']; let q = ''; for (const k of ['query', ...aliases]) { const v = String(args[k] ?? '').trim(); if (v) { q = v; break; } } if (!q && args.dayType != null) { const key = String(args.dayType).trim(); q = DAY_TYPE_TO_QUERY[key] || DAY_TYPE_TO_QUERY[key.toUpperCase()] || ''; } if (!q && userInput) q = inferTimetableQuery(userInput); if (q) q = normalizeTimetableQuery(q); return q; } const EXTRACTORS = { timetableQuery: { infer: inferTimetableQuery, normalize: normalizeTimetableQuery, resolve: resolveTimetableQuery, }, userInputAsIs: { infer: (text) => String(text || '').trim(), }, }; const TOOL_PARAM_RULES = { metro_load_timetable_full: [{ field: 'query', aliases: ['fileName', 'name', 'timetableName'], extract: 'timetableQuery', }], metro_search_tools: [{ field: 'query', extract: 'userInputAsIs', onlyIfEmpty: true, }], }; function readFieldValue(args, field, aliases = []) { const keys = [field, ...aliases]; for (const k of keys) { const v = String(args[k] ?? '').trim(); if (v) return v; } return ''; } function applyExtractor(name, value, userInput, args) { const ext = EXTRACTORS[name]; if (!ext) return value; if (ext.resolve) return ext.resolve(args || {}, userInput); let v = value; if (!v && userInput && ext.infer) v = ext.infer(userInput); if (v && ext.normalize) v = ext.normalize(v); return v; } const SETUP_CONFIRM_TOOLS = new Set(['metro_setup_rest_rules', 'metro_setup_handover_rules']); const RULES_CONFIRM_RE = /^(确认|可以|没问题|执行|好的|同意|按这个|就这样|确认执行|确认设置)([。.!!\s]*)$/; const RULES_CONFIRM_LOOSE_RE = /确认(执行|设置|应用|写入)?|按(这个|此)?(清单|方案|规则)?(执行|设置|应用)?/; function findLastProposedRules(messages) { if (!Array.isArray(messages)) return null; for (let i = messages.length - 1; i >= 0; i--) { const m = messages[i]; if (m?.role !== 'tool') continue; try { const parsed = typeof m.content === 'string' ? JSON.parse(m.content) : m.content; const result = parsed?.result || parsed; if (Array.isArray(result?.proposedRules) && result.proposedRules.length) { return result.proposedRules; } } catch (_) { } } return null; } function applySetupConfirmFromDialog(out, currentUserInput, messages) { const ui = String(currentUserInput || '').trim(); if (!ui) return; const wantsConfirm = RULES_CONFIRM_RE.test(ui) || RULES_CONFIRM_LOOSE_RE.test(ui); if (!wantsConfirm) return; out.stage = 'write'; out.confirmed = true; if (!Array.isArray(out.rules) || out.rules.length === 0) { const pending = findLastProposedRules(messages); if (pending?.length) out.rules = pending; } } export function enrichToolArguments(toolName, args, userInput, context = {}) { const out = { ...(args || {}) }; const ui = String(userInput || '').trim(); const dialog = [context.recentDialog, ui].filter(Boolean).join('\n'); if (ui) out._userContext = ui; const ctx = sessionContext.getState(); const sessionSnapshot = {}; if (ctx.currentEmployeeId) sessionSnapshot.currentEmployeeId = ctx.currentEmployeeId; if (ctx.currentEmployeeName) sessionSnapshot.currentEmployeeName = ctx.currentEmployeeName; if (ctx.currentTeam) sessionSnapshot.currentTeam = ctx.currentTeam; if (ctx.currentMonth) sessionSnapshot.currentMonth = ctx.currentMonth; if (ctx.lastQueryType) sessionSnapshot.lastQueryType = ctx.lastQueryType; if (Object.keys(sessionSnapshot).length > 0) { out._sessionContext = sessionSnapshot; } sessionContext.updateFromUserInput(ui); const rules = TOOL_PARAM_RULES[toolName]; if (rules) { for (const rule of rules) { let val = readFieldValue(out, rule.field, rule.aliases); if (rule.onlyIfEmpty && val) { out[rule.field] = val; continue; } val = applyExtractor(rule.extract, val, ui, out); if (val) out[rule.field] = val; } } if (toolName === 'metro_load_timetable_full') { if (out.query && out.dayType) delete out.dayType; applyAutoConfirmFromDialog(out, dialog, ui); } if (SETUP_CONFIRM_TOOLS.has(toolName)) { applySetupConfirmFromDialog(out, ui, context.messages); } const userYearText = buildUserYearSourceText(ui, context.messages); stripInventedProfileYear(toolName, out, userYearText); normalizeProfileEmployeeArgs(toolName, out, ui, dialog); if (Array.isArray(out.rules)) { out.rules = out.rules.map(normalizeRuleFields); } return out; } function normalizeProfileEmployeeArgs(toolName, out, userInput, dialog) { if (!String(toolName || '').startsWith('profile_')) return; const id = out.employeeId; if (id != null && String(id).trim() && /[\u4e00-\u9fff]/.test(String(id))) { if (!out.employeeName) out.employeeName = String(id).trim(); delete out.employeeId; } if (!out.employeeName && userInput) { const m = String(dialog || userInput).match( /(?:查看|查一下|查询|生成.*?|帮我看|看看)?\s*([一-龥·]{2,4})\s*(?:的|老师傅|师傅)?(?:数据|画像|报告|评估)?/ ); const m2 = String(userInput).match(/([一-龥·]{2,4})的(?:数据|画像|报告|评估|考试|公里)/); if (m2) out.employeeName = m2[1]; } if (out.month === 0 || out.month === '0') delete out.month; } function buildUserYearSourceText(userInput, messages) { const parts = []; if (Array.isArray(messages)) { for (const m of messages) { if (m?.role === 'user' && typeof m.content === 'string' && m.content.trim()) { parts.push(m.content.trim()); } } } const ui = String(userInput || '').trim(); if (ui && !parts.includes(ui)) parts.push(ui); return parts.join('\n'); } function stripInventedProfileYear(toolName, out, userText) { if (!String(toolName || '').startsWith('profile_')) return; if (out.year == null || out.year === '') return; const y = Number(out.year); if (!Number.isFinite(y)) { delete out.year; return; } const allowed = extractExplicitYears(userText); if (!allowed.includes(y)) { delete out.year; } } export function extractExplicitYears(text) { const years = []; const s = String(text || ''); const re = /(20\d{2})\s*年(?:度)?/g; let m; while ((m = re.exec(s))) { const y = parseInt(m[1], 10); if (!years.includes(y)) years.push(y); } return years; } const FIELD_ALIASES = { stationName: ['stationName', 'siteId', 'siteName', 'stationId', 'station', 'name'], count: ['count', 'num', 'number', 'people', 'persons', 'amount'], startTime: ['startTime', 'start', 'begin', 'from', 'start_time'], endTime: ['endTime', 'end', 'to', 'until', 'end_time'], reason: ['reason', 'type', 'category'], shift: ['shift', 'shiftType', '班制'], }; function normalizeRuleFields(rule) { if (!rule || typeof rule !== 'object') return rule; const out = {}; for (const [canonical, aliases] of Object.entries(FIELD_ALIASES)) { for (const alias of aliases) { if (rule[alias] !== undefined) { out[canonical] = rule[alias]; break; } } } for (const [k, v] of Object.entries(rule)) { if (!Object.values(FIELD_ALIASES).flat().includes(k)) { out[k] = v; } } return out; } const AUTO_CONFIRM_DENY_RE = /不要删|不删|保留(?:部分)?|取消删除|别删|无需删除/; const AUTO_CONFIRM_YES_RE = /自动(?:确认)?删除|直接(?:帮您)?(?:确认)?删除|不用问|自己删除|自动处理调试车|确认删除调试车|加载完成(?:后|时).{0,16}删(?:除)?调试车|会直接.{0,12}删(?:除)?调试车|直接帮您确认删除/i; function applyAutoConfirmFromDialog(out, dialog, currentUserInput) { if (out.autoConfirmDebugTrain === true) return; const deny = AUTO_CONFIRM_DENY_RE.test(String(currentUserInput || '')); if (deny) { out.autoConfirmDebugTrain = false; return; } if (AUTO_CONFIRM_YES_RE.test(String(dialog || ''))) { out.autoConfirmDebugTrain = true; } } export function buildRecentDialogText(messages, maxItems = 14) { return (messages || []) .filter(m => m.role === 'user' || m.role === 'assistant') .slice(-maxItems) .map(m => String(m.content || '').trim()) .filter(Boolean) .join('\n'); }