#!/usr/bin/env node /** * Verify Rain mode: full meinput load + LLM → Goose handoff. * * Usage: * MEMIND_USERNAME=john MEMIND_PASSWORD=981122tj node scripts/verify-rain-chat.mjs */ import { loadH5Environment } from './load-env.mjs'; import { createAgentRun, createReporter, extractAssistantTexts, getSession, loginViaApi, resolvePortalBase, waitForAssistantGrowth, waitForRunTerminal, } from './scenario-test-lib.mjs'; import { RAIN_SKILL_NAME } from '../chat-skills.mjs'; loadH5Environment(import.meta.dirname); const QUERY = process.env.RAIN_VERIFY_QUERY ?? '最近我输入了什么?'; const baseUrl = (process.env.MEMIND_BASE_URL ?? resolvePortalBase(Number(process.env.H5_PORT ?? 8081))).replace(/\/$/, ''); const account = { username: process.env.MEMIND_USERNAME ?? 'john', password: process.env.MEMIND_PASSWORD ?? process.env.JOHN_PASSWORD ?? '981122tj', }; async function main() { const reporter = createReporter(); console.log(`==> Rain verify\n Portal: ${baseUrl}\n User: ${account.username}\n Query: ${QUERY}\n`); const auth = await loginViaApi(baseUrl, account, reporter); const run = await createAgentRun(baseUrl, auth.cookie, { message: QUERY, selectedChatSkill: RAIN_SKILL_NAME, }); // Patch message shape for rain metadata (createAgentRun uses buildUserMessage) reporter.pass('发起 Rain run', run.runId); const terminal = await waitForRunTerminal(baseUrl, auth.cookie, run.runId, 180000); if (terminal.status !== 'succeeded') { const errText = String(terminal.error ?? terminal.lastError ?? ''); if (/Arrearage|Access denied/i.test(errText)) { reporter.fail('run 终态', `LLM 账户欠费/不可用,非 Rain 逻辑错误:${errText.slice(0, 120)}`); } else { reporter.fail('run 终态', terminal.status ?? errText.slice(0, 120) ?? 'unknown'); } } else { reporter.pass('run 终态', 'succeeded'); } const sessionId = run.sessionId ?? terminal.sessionId ?? terminal.agent_session_id; const session = await getSession(baseUrl, auth.cookie, sessionId); const texts = extractAssistantTexts(session.session ?? session.payload ?? session); const reply = texts.join('\n').trim(); if (!reply) { reporter.fail('助手回复', '空'); } else { console.log('\n--- assistant ---\n', reply.slice(0, 800), '\n---\n'); reporter.pass('助手回复', `${reply.length} 字符`); if (/疲惫|车载冰箱|便签页面内容对所有人可见|TKMind 记忆系统/u.test(reply) && !/MeInput|输入|项目|手机|Rain/u.test(reply)) { reporter.fail('注入隔离', '回复像 Memory V2,未体现 MeInput'); } else { reporter.pass('注入隔离', '未检测到典型长期记忆污染'); } if (/0\.\d{4}/.test(reply) && /关联值|评分|权重/u.test(reply)) { reporter.fail('分数泄漏', '回复含 recall 分数语义'); } else { reporter.pass('分数泄漏', '未检测到'); } } process.exit(reporter.summary()); } main().catch((err) => { console.error(err); process.exit(1); });