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

91 lines
2.9 KiB
JavaScript

import { RAIN_SKILL_NAME, isRainModeMessage } from '../chat-skills.mjs';
import { loadRainMeinputRecords, formatMeinputFullBlock } from './meinput-full.mjs';
import { runRainLlmAnalysis, buildRainGooseHandoffText, stripRainSkillPrefix } from './llm-analysis.mjs';
import { resolveRainTimeRange, formatRainTimeRangeLabel } from './time-range.mjs';
export { RAIN_SKILL_NAME, isRainModeMessage };
export { resolveRainTimeRange, formatRainTimeRangeLabel, RAIN_DEFAULT_DAYS } from './time-range.mjs';
export { formatMeinputFullBlock, loadRainMeinputRecords } from './meinput-full.mjs';
export { runRainLlmAnalysis, buildRainGooseHandoffText, stripRainSkillPrefix } from './llm-analysis.mjs';
/**
* @param {{
* llmProviderService: object,
* userId: string,
* userMessage: object,
* }} input
* @returns {Promise<
* | { phase: 'clarify', userReply: string, rainMeta: object }
* | { phase: 'goose', gooseHandoffText: string, userReply: string, rainMeta: object }
* >}
*/
export async function executeRainPipeline(input) {
const displayText =
input.userMessage?.metadata?.displayText ??
stripRainSkillPrefix(
Array.isArray(input.userMessage?.content)
? input.userMessage.content
.filter((item) => item?.type === 'text')
.map((item) => item.text ?? '')
.join('\n')
: String(input.userMessage?.content ?? ''),
);
const timeResolution = resolveRainTimeRange(displayText);
if (timeResolution.needsClarification) {
return {
phase: 'clarify',
userReply: timeResolution.clarificationQuestion,
rainMeta: { timeResolution, recordCount: 0 },
};
}
const timeRangeLabel = formatRainTimeRangeLabel(timeResolution.range, timeResolution);
const { records } = await loadRainMeinputRecords({
userId: input.userId,
range: timeResolution.range,
});
const meinputBlock = formatMeinputFullBlock(records, {
range: timeResolution.range,
label: timeResolution.label,
source: timeResolution.source,
});
const analysis = await runRainLlmAnalysis({
llmProviderService: input.llmProviderService,
userQuery: displayText,
meinputBlock,
timeRangeLabel,
recordCount: records.length,
});
if (analysis.needs_clarification && analysis.clarification_question) {
return {
phase: 'clarify',
userReply: analysis.clarification_question,
rainMeta: { timeResolution, recordCount: records.length, analysis },
};
}
const gooseHandoffText = buildRainGooseHandoffText({
userQuery: displayText,
timeRangeLabel,
recordCount: records.length,
analysis: analysis.meinput_analysis,
userGoal: analysis.user_goal,
suggestedNextSteps: analysis.suggested_next_steps,
});
return {
phase: 'goose',
gooseHandoffText,
userReply: analysis.user_reply,
rainMeta: {
timeResolution,
recordCount: records.length,
analysis,
meinputBlockChars: meinputBlock.length,
},
};
}