fix(page-data): deliver WeChat surveys when agent pre-binds pages
Memind CI / Test, build, and release guards (push) Failing after 5s
Memind CI / Test, build, and release guards (push) Failing after 5s
Include already_bound auto-bind skips and request-scoped relative paths when building Page Data delivery artifacts, so pre-bound survey pages are verified and linked instead of failing the finish guard. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -108,16 +108,44 @@ export function rewritePageDataDeliveryLinks(text, artifacts = []) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildPageDataDeliveryArtifactsFromBindResult(autoBind, publishDir, options = {}) {
|
function collectPageDataDeliveryRelativePaths(autoBind, relevantRelativePaths = null) {
|
||||||
|
const deliveryPaths = new Set();
|
||||||
|
for (const item of autoBind?.bound ?? []) {
|
||||||
|
if (item?.relativePath) deliveryPaths.add(item.relativePath);
|
||||||
|
}
|
||||||
|
for (const item of autoBind?.skipped ?? []) {
|
||||||
|
if (item?.reason === 'already_bound' && item?.relativePath) {
|
||||||
|
deliveryPaths.add(item.relativePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Array.isArray(relevantRelativePaths)) {
|
||||||
|
for (const relativePath of relevantRelativePaths) {
|
||||||
|
if (relativePath) deliveryPaths.add(relativePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deliveryPaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildPageDataDeliveryArtifactsFromBindResult(
|
||||||
|
autoBind,
|
||||||
|
publishDir,
|
||||||
|
options = {},
|
||||||
|
relevantRelativePaths = null,
|
||||||
|
) {
|
||||||
const boundUrls = new Map(
|
const boundUrls = new Map(
|
||||||
(autoBind?.bound ?? [])
|
(autoBind?.bound ?? [])
|
||||||
.filter((item) => item?.relativePath && item?.workspaceUrl)
|
.filter((item) => item?.relativePath && item?.workspaceUrl)
|
||||||
.map((item) => [item.relativePath, item.workspaceUrl]),
|
.map((item) => [item.relativePath, item.workspaceUrl]),
|
||||||
);
|
);
|
||||||
// Only verify/deliver pages bound in this auto-bind pass. Scanning the whole
|
const deliveryPaths = collectPageDataDeliveryRelativePaths(
|
||||||
|
autoBind,
|
||||||
|
relevantRelativePaths,
|
||||||
|
);
|
||||||
|
// Limit verification/delivery to this request's bound pages. Scanning the whole
|
||||||
// workspace lets one stale historical Page Data page fail delivery for a new survey.
|
// workspace lets one stale historical Page Data page fail delivery for a new survey.
|
||||||
|
if (deliveryPaths.size === 0) return [];
|
||||||
return collectPageDataDeliveryArtifacts(publishDir, options)
|
return collectPageDataDeliveryArtifacts(publishDir, options)
|
||||||
.filter((artifact) => boundUrls.has(artifact.relativePath))
|
.filter((artifact) => deliveryPaths.has(artifact.relativePath))
|
||||||
.map((artifact) => ({
|
.map((artifact) => ({
|
||||||
...artifact,
|
...artifact,
|
||||||
url: boundUrls.get(artifact.relativePath) ?? artifact.url,
|
url: boundUrls.get(artifact.relativePath) ?? artifact.url,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import test from 'node:test';
|
|||||||
import {
|
import {
|
||||||
buildPageDataCollectFailureText,
|
buildPageDataCollectFailureText,
|
||||||
buildPageDataCollectRepairPrompt,
|
buildPageDataCollectRepairPrompt,
|
||||||
|
buildPageDataDeliveryArtifactsFromBindResult,
|
||||||
collectPageDataDeliveryArtifacts,
|
collectPageDataDeliveryArtifacts,
|
||||||
evaluatePageDataFinishGuard,
|
evaluatePageDataFinishGuard,
|
||||||
evaluatePageDataFinishGuardAsync,
|
evaluatePageDataFinishGuardAsync,
|
||||||
@@ -306,6 +307,34 @@ test('evaluatePageDataFinishGuard flags html when dataset is not registered', as
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('buildPageDataDeliveryArtifactsFromBindResult includes already_bound pages for this request only', () => {
|
||||||
|
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'page-data-guard-bind-result-'));
|
||||||
|
const previousBase = process.env.H5_PUBLIC_BASE_URL;
|
||||||
|
process.env.H5_PUBLIC_BASE_URL = 'https://m.tkmind.cn';
|
||||||
|
try {
|
||||||
|
fs.mkdirSync(path.join(publishDir, 'public'), { recursive: true });
|
||||||
|
fs.writeFileSync(path.join(publishDir, 'public', 'new-survey.html'), SURVEY_HTML, 'utf8');
|
||||||
|
fs.writeFileSync(path.join(publishDir, 'public', 'stale-survey.html'), SURVEY_HTML, 'utf8');
|
||||||
|
const autoBind = {
|
||||||
|
bound: [],
|
||||||
|
skipped: [{ relativePath: 'public/new-survey.html', reason: 'already_bound' }],
|
||||||
|
errors: [],
|
||||||
|
};
|
||||||
|
const artifacts = buildPageDataDeliveryArtifactsFromBindResult(
|
||||||
|
autoBind,
|
||||||
|
publishDir,
|
||||||
|
{},
|
||||||
|
['public/new-survey.html'],
|
||||||
|
);
|
||||||
|
assert.equal(artifacts.length, 1);
|
||||||
|
assert.equal(artifacts[0].relativePath, 'public/new-survey.html');
|
||||||
|
} finally {
|
||||||
|
if (previousBase == null) delete process.env.H5_PUBLIC_BASE_URL;
|
||||||
|
else process.env.H5_PUBLIC_BASE_URL = previousBase;
|
||||||
|
fs.rmSync(publishDir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('collectPageDataDeliveryArtifacts uses Portal base when H5_PUBLIC_BASE_URL points at Vite', () => {
|
test('collectPageDataDeliveryArtifacts uses Portal base when H5_PUBLIC_BASE_URL points at Vite', () => {
|
||||||
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'page-data-guard-portal-url-'));
|
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'page-data-guard-portal-url-'));
|
||||||
const previousBase = process.env.H5_PUBLIC_BASE_URL;
|
const previousBase = process.env.H5_PUBLIC_BASE_URL;
|
||||||
|
|||||||
@@ -283,6 +283,9 @@ export function createMindSpacePublicFinishService({
|
|||||||
pageService.findPageByRelativePath.bind(
|
pageService.findPageByRelativePath.bind(
|
||||||
pageService,
|
pageService,
|
||||||
);
|
);
|
||||||
|
const relevantRelativePaths = (outcome?.evaluation?.relevantFiles ?? [])
|
||||||
|
.map((file) => file?.relativePath)
|
||||||
|
.filter(Boolean);
|
||||||
autoBind =
|
autoBind =
|
||||||
await maybeAutoBindPageDataHtmlPagesFn({
|
await maybeAutoBindPageDataHtmlPagesFn({
|
||||||
pool,
|
pool,
|
||||||
@@ -291,6 +294,10 @@ export function createMindSpacePublicFinishService({
|
|||||||
h5Root,
|
h5Root,
|
||||||
storageRoot,
|
storageRoot,
|
||||||
findPageByRelativePath,
|
findPageByRelativePath,
|
||||||
|
onlyRelativePaths:
|
||||||
|
relevantRelativePaths.length > 0
|
||||||
|
? relevantRelativePaths
|
||||||
|
: null,
|
||||||
});
|
});
|
||||||
outcome =
|
outcome =
|
||||||
await resolvePageDataCollectOutcomeAsyncFn({
|
await resolvePageDataCollectOutcomeAsyncFn({
|
||||||
@@ -308,11 +315,15 @@ export function createMindSpacePublicFinishService({
|
|||||||
let deliveryCheck = null;
|
let deliveryCheck = null;
|
||||||
let rewrittenText = normalizedReply.text;
|
let rewrittenText = normalizedReply.text;
|
||||||
if (outcome?.action === 'send') {
|
if (outcome?.action === 'send') {
|
||||||
|
const deliveryRelativePaths = (outcome?.evaluation?.relevantFiles ?? [])
|
||||||
|
.map((file) => file?.relativePath)
|
||||||
|
.filter(Boolean);
|
||||||
deliveryArtifacts =
|
deliveryArtifacts =
|
||||||
buildPageDataDeliveryArtifactsFromBindResultFn(
|
buildPageDataDeliveryArtifactsFromBindResultFn(
|
||||||
autoBind,
|
autoBind,
|
||||||
publishDir,
|
publishDir,
|
||||||
{ publicBaseUrl },
|
{ publicBaseUrl },
|
||||||
|
deliveryRelativePaths,
|
||||||
);
|
);
|
||||||
if (deliveryArtifacts.length > 0) {
|
if (deliveryArtifacts.length > 0) {
|
||||||
deliveryCheck =
|
deliveryCheck =
|
||||||
|
|||||||
Reference in New Issue
Block a user