Files
memind/scripts/check-goosed-v149-page-e2e.mjs
T

164 lines
5.2 KiB
JavaScript
Raw Normal View History

#!/usr/bin/env node
/**
* Portal + Goose v1.49 page E2E: agent/runs → Finish → HTML materialize + public link.
*/
import crypto from 'node:crypto';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { buildChatSkillPrompt } from '../chat-skills.mjs';
import { prepareGooseV149CheckEnv } from './goose-v149-canary.mjs';
import { enforceRealLlmGate } from './goose-v149-real-llm-gate.mjs';
import {
createReporter,
extractAssistantTexts,
getSession,
loginViaApi,
resolvePortalBase,
verifyPageAccess,
waitForAssistantGrowth,
waitForRunTerminal,
} from './scenario-test-lib.mjs';
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
enforceRealLlmGate('check-goosed-v149-page-e2e.mjs');
prepareGooseV149CheckEnv(process.env, root);
const baseUrl = resolvePortalBase(Number(process.env.H5_PORT ?? 8081));
const skip = process.env.GOOSE_V149_PAGE_E2E_SKIP === '1';
const timeoutMs = Number(process.env.GOOSE_V149_PAGE_E2E_TIMEOUT_MS || 600_000);
async function portalReachable() {
try {
const response = await fetch(`${baseUrl}/auth/status`);
return response.ok;
} catch {
return false;
}
}
async function createGoosedPageRun(baseUrl, cookie, { sessionId, message }) {
const requestId = crypto.randomUUID();
const response = await fetch(`${baseUrl}/api/agent/runs`, {
method: 'POST',
headers: {
Cookie: cookie,
'Content-Type': 'application/json',
},
body: JSON.stringify({
request_id: requestId,
session_id: sessionId,
force_deep_reasoning: true,
user_message: {
id: crypto.randomUUID(),
role: 'user',
created: Math.floor(Date.now() / 1000),
content: [{ type: 'text', text: message }],
metadata: {
userVisible: true,
agentVisible: true,
displayText: message,
},
},
}),
});
const payload = await response.json().catch(() => ({}));
if (!response.ok) {
throw new Error(`POST /api/agent/runs ${response.status}: ${JSON.stringify(payload).slice(0, 400)}`);
}
const run = payload.run ?? payload;
return {
runId: run.id,
requestId,
sessionId: run.sessionId ?? run.agent_session_id ?? sessionId,
};
}
async function main() {
if (skip || !(await portalReachable())) {
console.log(`GOOSE_V149_PAGE_E2E_SKIP: Portal not running at ${baseUrl}`);
console.log('GOOSE_V149_PAGE_E2E_OK: skipped');
return;
}
const reporter = createReporter();
const username = process.env.RELEASE_GATE_SCENARIO_USERNAME ?? 'john';
const password =
process.env.JOHN_PASSWORD
?? process.env.H5_ACCESS_PASSWORD
?? process.env.MEMIND_PASSWORD
?? '';
if (!password) {
throw new Error('set JOHN_PASSWORD (or H5_ACCESS_PASSWORD) for page E2E');
}
const auth = await loginViaApi(baseUrl, { username, password }, reporter);
const startRes = await fetch(`${baseUrl}/api/agent/start`, {
method: 'POST',
headers: { Cookie: auth.cookie, 'Content-Type': 'application/json' },
body: JSON.stringify({}),
});
const started = await startRes.json().catch(() => ({}));
if (!startRes.ok || !started?.id) {
throw new Error(`agent/start failed: ${startRes.status}`);
}
const sessionId = started.id;
const skillPrefix = buildChatSkillPrompt('generate-page', 'static-page-publish');
const pageName = `goose-v149-portal-e2e-${Date.now()}.html`;
const message =
`${skillPrefix}请做一个全新的苏州一日游攻略页面,保存为 public/${pageName},`
+ '不要修改已有页面,完成后在回复里给出可访问链接。';
const run = await createGoosedPageRun(baseUrl, auth.cookie, { sessionId, message });
const terminal = await waitForRunTerminal(baseUrl, auth.cookie, run.runId, timeoutMs);
if (terminal.status !== 'succeeded') {
throw new Error(`agent run failed: ${terminal.status} ${terminal.error ?? ''}`);
}
reporter.pass('agent run', terminal.status);
const activeSessionId = terminal.sessionId ?? terminal.agent_session_id ?? run.sessionId ?? sessionId;
const reply = await waitForAssistantGrowth(baseUrl, auth.cookie, activeSessionId, {
minChars: 20,
timeoutMs: Math.min(timeoutMs, 120_000),
});
if (!reply?.combined) {
throw new Error('assistant reply missing after page run');
}
reporter.pass('assistant 回复', `${reply.combined.length} 字`);
const sessionDetail = await getSession(baseUrl, auth.cookie, activeSessionId);
const assistantCount = sessionDetail.ok
? extractAssistantTexts(sessionDetail.session).length
: 0;
if (assistantCount <= 0) {
throw new Error('session conversation has no assistant messages after page run');
}
const pageOk = await verifyPageAccess({
baseUrl,
cookie: auth.cookie,
publishKey: auth.userId,
replyText: reply.combined,
expect: {
keywords: ['苏州'],
requirePublicLink: true,
requireHttp200: true,
},
reporter,
});
if (!pageOk) {
throw new Error('page delivery verification failed');
}
console.log(
`GOOSE_V149_PAGE_E2E_OK: session=${activeSessionId} run=${run.runId} `
+ `assistantChars=${reply.combined.length} base=${baseUrl}`,
);
}
main().catch((error) => {
console.error(`GOOSE_V149_PAGE_E2E_FAIL: ${error.message}`);
process.exit(1);
});