fix: fail closed when WeChat page.generate has no HTML artifact
Prevent text-only planning replies from marking WeChat delivery done when static-page-publish never confirmed a public HTML file. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+6
-5
@@ -3288,8 +3288,8 @@ test('wechat mp service forwards H5 agent text when page generation produced no
|
|||||||
assert.equal(fs.existsSync(htmlPath), false);
|
assert.equal(fs.existsSync(htmlPath), false);
|
||||||
const sendCall = wechatCalls.find(([url]) => String(url).includes('/cgi-bin/message/custom/send'));
|
const sendCall = wechatCalls.find(([url]) => String(url).includes('/cgi-bin/message/custom/send'));
|
||||||
const payload = JSON.parse(sendCall[2]);
|
const payload = JSON.parse(sendCall[2]);
|
||||||
assert.match(payload.text.content, /🌴 泰国简易攻略/);
|
assert.doesNotMatch(payload.text.content, /🌴 泰国简易攻略/);
|
||||||
assert.doesNotMatch(payload.text.content, /没有按 H5 里的页面技能真正生成成功/);
|
assert.match(payload.text.content, /没有按服务号页面技能真正生成成功/);
|
||||||
assert.doesNotMatch(payload.text.content, /https:\/\/m\.tkmind\.cn\/MindSpace\/.+\/public\/thailand-guide\.html/);
|
assert.doesNotMatch(payload.text.content, /https:\/\/m\.tkmind\.cn\/MindSpace\/.+\/public\/thailand-guide\.html/);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -3631,7 +3631,8 @@ test('wechat mp service recreates dedicated session when tool_calls error arrive
|
|||||||
assert.equal(started, true);
|
assert.equal(started, true);
|
||||||
const sendCall = wechatCalls.find(([url]) => String(url).includes('/cgi-bin/message/custom/send'));
|
const sendCall = wechatCalls.find(([url]) => String(url).includes('/cgi-bin/message/custom/send'));
|
||||||
const payload = JSON.parse(sendCall[2]);
|
const payload = JSON.parse(sendCall[2]);
|
||||||
assert.match(payload.text.content, /已恢复,可以继续对话/);
|
assert.doesNotMatch(payload.text.content, /已恢复,可以继续对话/);
|
||||||
|
assert.match(payload.text.content, /没有按服务号页面技能真正生成成功/);
|
||||||
assert.doesNotMatch(payload.text.content, /Bad request/);
|
assert.doesNotMatch(payload.text.content, /Bad request/);
|
||||||
assert.doesNotMatch(payload.text.content, /tool_calls/);
|
assert.doesNotMatch(payload.text.content, /tool_calls/);
|
||||||
});
|
});
|
||||||
@@ -3965,8 +3966,8 @@ test('wechat mp service retries poisoned publish claims before forwarding H5 ret
|
|||||||
const sendCall = wechatCalls.find(([url]) => String(url).includes('/cgi-bin/message/custom/send'));
|
const sendCall = wechatCalls.find(([url]) => String(url).includes('/cgi-bin/message/custom/send'));
|
||||||
const payload = JSON.parse(sendCall[2]);
|
const payload = JSON.parse(sendCall[2]);
|
||||||
assert.doesNotMatch(payload.text.content, /页面都已经成功发布了|主题页面已发布/);
|
assert.doesNotMatch(payload.text.content, /页面都已经成功发布了|主题页面已发布/);
|
||||||
assert.match(payload.text.content, /🌴 夏日主题页面/);
|
assert.doesNotMatch(payload.text.content, /🌴 夏日主题页面/);
|
||||||
assert.doesNotMatch(payload.text.content, /没有按 H5 里的页面技能真正生成成功/);
|
assert.match(payload.text.content, /没有按服务号页面技能真正生成成功/);
|
||||||
assert.doesNotMatch(payload.text.content, /summer-breeze-journal\.html/);
|
assert.doesNotMatch(payload.text.content, /summer-breeze-journal\.html/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -69,5 +69,11 @@ export function resolvePageGenerateOutcome({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return { action: 'send', artifacts: sendable };
|
// Fail closed: page.generate must deliver a verified public HTML artifact.
|
||||||
|
// Text-only planning replies ("我先搜索…") must not mark WeChat delivery done.
|
||||||
|
return {
|
||||||
|
action: 'fail',
|
||||||
|
failureText: buildPagePublishFailureText(),
|
||||||
|
reason: 'missing_page_artifact',
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,3 +218,29 @@ test('resolvePageGenerateOutcome sends when share preview meta is present', () =
|
|||||||
assert.equal(outcome.action, 'send');
|
assert.equal(outcome.action, 'send');
|
||||||
assert.equal(outcome.artifacts.length, 1);
|
assert.equal(outcome.artifacts.length, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('resolvePageGenerateOutcome fails closed on planning text without html artifact', () => {
|
||||||
|
const outcome = resolvePageGenerateOutcome({
|
||||||
|
reply: {
|
||||||
|
text: '找到了之前的新闻页面。让我先读取最新的页面格式作为参考,同时并行搜索今日新闻和天气。',
|
||||||
|
},
|
||||||
|
confirmedArtifacts: [],
|
||||||
|
verifiedArtifacts: [],
|
||||||
|
});
|
||||||
|
assert.equal(outcome.action, 'fail');
|
||||||
|
assert.equal(outcome.reason, 'missing_page_artifact');
|
||||||
|
assert.match(outcome.failureText, /没有按服务号页面技能真正生成成功|static-page-publish/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('resolvePageGenerateOutcome fails closed when reply links an old page but no artifact confirmed', () => {
|
||||||
|
const outcome = resolvePageGenerateOutcome({
|
||||||
|
reply: {
|
||||||
|
text: '[每日新闻](https://m.tkmind.cn/MindSpace/u/public/daily-news-0728.html)',
|
||||||
|
},
|
||||||
|
confirmedArtifacts: [],
|
||||||
|
verifiedArtifacts: [],
|
||||||
|
replyHasPublicLinks: true,
|
||||||
|
});
|
||||||
|
assert.equal(outcome.action, 'fail');
|
||||||
|
assert.equal(outcome.reason, 'missing_page_artifact');
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user