Files
memind/rain-service.test.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

100 lines
3.9 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { resolveRainTimeRange, RAIN_DEFAULT_DAYS } from './rain-service/time-range.mjs';
import { formatMeinputFullBlock } from './rain-service/meinput-full.mjs';
import { buildRainGooseHandoffText, stripRainSkillPrefix } from './rain-service/llm-analysis.mjs';
import {
RAIN_SKILL_NAME,
isRainModeMessage,
filterChatSkills,
CHAT_SKILL_DEFINITIONS,
} from './chat-skills.mjs';
test('resolveRainTimeRange defaults to 3 days when no time hint', () => {
const now = new Date('2026-09-04T12:00:00+08:00');
const result = resolveRainTimeRange('帮我总结最近的输入', now);
assert.equal(result.needsClarification, false);
assert.equal(result.source, 'default_3d');
assert.ok(result.range?.start);
assert.ok(result.range?.end);
const spanMs =
new Date(result.range.end).getTime() - new Date(result.range.start).getTime();
assert.ok(spanMs >= RAIN_DEFAULT_DAYS * 24 * 60 * 60 * 1000 - 60_000);
});
test('resolveRainTimeRange asks clarification for ambiguous phrases', () => {
const result = resolveRainTimeRange('前几天我在做什么', new Date('2026-09-04T12:00:00+08:00'));
assert.equal(result.needsClarification, true);
assert.match(result.clarificationQuestion ?? '', /起止时间/);
});
test('resolveRainTimeRange parses yesterday explicitly', () => {
const now = new Date('2026-09-04T12:00:00+08:00');
const result = resolveRainTimeRange('我昨天输入了什么', now);
assert.equal(result.needsClarification, false);
assert.equal(result.source, 'user_explicit');
assert.equal(result.label, 'yesterday');
});
test('formatMeinputFullBlock lists every record with timestamp', () => {
const block = formatMeinputFullBlock(
[
{
created_at: '2026-09-02T19:42:16.541Z',
text: '项目',
app_name: 'Cursor',
app_bundle_id: 'com.cursor',
},
{
created_at: '2026-09-02T19:46:15.181Z',
text: '手机',
app_name: null,
app_bundle_id: 'com.apple.mobile',
},
],
{
range: { start: '2026-09-01T00:00:00.000Z', end: '2026-09-04T00:00:00.000Z' },
label: '近3天',
},
);
assert.match(block, /MeInput 原始输入 · Rain/);
assert.match(block, /项目/);
assert.match(block, /手机/);
assert.match(block, /2026-09-02 19:42:16/);
assert.doesNotMatch(block, /0\.2795/);
});
test('buildRainGooseHandoffText carries analysis to agent', () => {
const text = buildRainGooseHandoffText({
userQuery: '最近我输入了什么',
timeRangeLabel: '近3天',
recordCount: 12,
analysis: '用户在 Cursor 中输入了项目相关词',
userGoal: '回顾输入',
suggestedNextSteps: ['给用户时间线总结'],
});
assert.match(text, /Rain · MeInput 分析简报/);
assert.match(text, /用户在 Cursor 中输入了项目相关词/);
assert.match(text, /最近我输入了什么/);
});
test('isRainModeMessage detects selected rain skill', () => {
assert.equal(
isRainModeMessage({ metadata: { memindRun: { selectedChatSkill: RAIN_SKILL_NAME } } }),
true,
);
assert.equal(isRainModeMessage({ metadata: { memindRun: { selectedChatSkill: 'web' } } }), false);
});
test('filterChatSkills hides page templates by default', () => {
const options = CHAT_SKILL_DEFINITIONS.map((def) => ({ ...def, buildPrompt: () => '' }));
const filtered = filterChatSkills(options, { grantedSkills: ['page-template-travel'], canPublish: true });
assert.ok(filtered.some((item) => item.id === RAIN_SKILL_NAME));
assert.equal(filtered.some((item) => item.id === 'page-template-travel'), false);
});
test('stripRainSkillPrefix removes rain prompt header', () => {
const text = stripRainSkillPrefix('【Rain · MeInput 输入分析】请描述要分析的时间区间和你的诉求。未写时间则默认近3天;区间不明确时我会先追问。我的问题是:总结输入');
assert.equal(text, '总结输入');
});