Files
memind/rain-service/time-range.mjs
T
john be464a5b8d
Memind CI / Test, build, and release guards (push) Has been cancelled
Add Rain V0 for MeInput full-range chat analysis and delivery tooling.
Introduce rain-service orchestration, browser-safe chat skill filtering, MeInput
adapter helpers, and verify/deploy scripts so Rain mode can summarize recent input
without Memory V2 pollution.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-04 13:49:40 +08:00

106 lines
3.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { parseTimeScope } from '../temporal-recall-service/time-parser.mjs';
export const RAIN_DEFAULT_DAYS = 3;
const TZ_OFFSET_MIN = Number(process.env.TEMPORAL_RECALL_TZ_OFFSET_MIN ?? 480);
/** @param {Date} anchor @param {number} deltaDays */
function addDays(anchor, deltaDays) {
const shifted = new Date(anchor.getTime() + TZ_OFFSET_MIN * 60_000);
const ms =
Date.UTC(
shifted.getUTCFullYear(),
shifted.getUTCMonth(),
shifted.getUTCDate() + deltaDays,
0,
0,
0,
0,
) - TZ_OFFSET_MIN * 60_000;
return new Date(ms);
}
/** @param {Date} anchor */
function endOfDay(anchor) {
const p = new Date(anchor.getTime() + TZ_OFFSET_MIN * 60_000);
const ms =
Date.UTC(p.getUTCFullYear(), p.getUTCMonth(), p.getUTCDate() + 1, 0, 0, 0, 0) -
TZ_OFFSET_MIN * 60_000;
return new Date(ms);
}
const AMBIGUOUS_TIME_PATTERNS = [
/前几天/u,
/那段(?:时间|日子)/u,
/上次(?:那)?(?:段|个)/u,
/大概.{0,6}(?:昨天|前天|上周|几)/u,
/左右/u,
/不太确定.{0,8}时间/u,
];
const EXPLICIT_TIME_HINT =
/昨天|昨日|今天|今日|明天|明日|前天|后天|上周|这周|本周|这个月|本月|上个月|\d{1,2}\s*月|\d{1,2}\s*[:]\d{2}|最近\s*\d+\s*天|最近一周|最近1周|\d{4}-\d{2}-\d{2}/u;
/**
* @param {string} query
* @param {Date} [now]
*/
export function resolveRainTimeRange(query, now = new Date()) {
const text = String(query ?? '').trim();
for (const pattern of AMBIGUOUS_TIME_PATTERNS) {
if (pattern.test(text)) {
return {
needsClarification: true,
clarificationQuestion:
'请说明要分析 MeInput 输入记录的起止时间(例如「9月2日 18:00 到 9月4日 10:00」,或「昨天全天」)。若你不补充,我将默认使用近 3 天。',
range: null,
source: 'ambiguous',
label: null,
};
}
}
if (!EXPLICIT_TIME_HINT.test(text)) {
const end = endOfDay(now);
const start = addDays(now, -RAIN_DEFAULT_DAYS);
return {
needsClarification: false,
range: { start: start.toISOString(), end: end.toISOString() },
source: 'default_3d',
label: `${RAIN_DEFAULT_DAYS}`,
};
}
const scope = parseTimeScope(text, now);
const isDefaultFallback =
scope.rule_hits?.includes('time:default_week') ||
scope.rule_hits?.includes('time:recent_fuzzy');
if (isDefaultFallback && /最近|近期|这几天/u.test(text) && !/最近\s*\d+\s*天/u.test(text)) {
const end = endOfDay(now);
const start = addDays(now, -RAIN_DEFAULT_DAYS);
return {
needsClarification: false,
range: { start: start.toISOString(), end: end.toISOString() },
source: 'default_3d',
label: `${RAIN_DEFAULT_DAYS}`,
};
}
return {
needsClarification: false,
range: scope.mention_range,
source: 'user_explicit',
label: scope.relative_label,
};
}
export function formatRainTimeRangeLabel(range, meta = {}) {
if (!range?.start || !range?.end) return meta.label ?? '未指定';
const start = range.start.slice(0, 16).replace('T', ' ');
const end = range.end.slice(0, 16).replace('T', ' ');
const suffix = meta.source === 'default_3d' ? '(默认近3天)' : '';
return `${start} ~ ${end}${suffix}`;
}