fix: allow page clarification turns without delivery error

This commit is contained in:
john
2026-07-24 17:37:05 +08:00
parent 54637beffb
commit 412e5f149b
5 changed files with 103 additions and 2 deletions
+19 -2
View File
@@ -16,7 +16,11 @@ import {
SESSION_FINISHED_STALE_GRACE_MS,
tryRecoverRunFromDeliverables,
} from './agent-run-deliverable-check.mjs';
import { isPageDataIntent, isPageGenerationIntent } from './chat-skills.mjs';
import {
isGenericPageGenerationRequest,
isPageDataIntent,
isPageGenerationIntent,
} from './chat-skills.mjs';
const DEFAULT_RUN_RETRY_DELAYS_MS = [1500, 5000, 15000];
const TERMINAL_STATUSES = new Set(['succeeded', 'failed']);
@@ -66,6 +70,14 @@ function extractRunMessageText(row) {
.join('\n');
}
function extractRunDisplayText(row) {
const message = parseDbJsonColumn(row?.user_message_json, {}) ?? {};
const displayText = message?.metadata?.displayText;
return typeof displayText === 'string' && displayText.trim()
? displayText.trim()
: extractRunMessageText(row);
}
function resolveRequiredImageGeneration(row, routing) {
const message = parseDbJsonColumn(row?.user_message_json, {}) ?? {};
const metadata = message.metadata ?? {};
@@ -894,11 +906,16 @@ export function createAgentRunGateway({
throw error;
}
const runMessageText = extractRunMessageText(row);
const runDisplayText = extractRunDisplayText(row);
const pageDataIntent = isPageDataIntent(runMessageText)
|| routing?.suggestedSkill === 'page-data-collect';
const pageGenerationIntent = isPageGenerationIntent(runMessageText)
|| routing?.suggestedSkill === 'static-page-publish';
const requiresPageDeliverable = pageDataIntent || pageGenerationIntent;
// A bare “generate a page” request has no subject to render. The assistant's
// clarification is a successful conversational turn, not a failed delivery.
// Once the user supplies a subject, the existing fail-closed guard still applies.
const requiresPageDeliverable = pageDataIntent
|| (pageGenerationIntent && !isGenericPageGenerationRequest(runDisplayText));
let deliverables = null;
if (requiresPageDeliverable || typeof validateRunDeliverables === 'function') {
const latest = await getRunById(runId);
+30
View File
@@ -536,6 +536,36 @@ test('static page run fails closed when Finish arrives without public HTML', asy
assert.match(pool.runs.get(run.id).error_message, /public HTML 交付物/);
});
test('generic page request succeeds when the assistant finishes a clarification turn', async () => {
const pool = createFakePool();
const gateway = createAgentRunGateway({
pool,
userAuth: {},
tkmindProxy: {
async startSessionForUser() {
return { id: 'session-public-page-clarification' };
},
async submitSessionReplyAndAwaitFinishForUser() {
return { ok: true, finishEvent: { type: 'Finish' } };
},
},
syncUserPagesOnSuccess: async () => ({}),
retryDelaysMs: [],
});
const run = await gateway.createRun('user-1', {
requestId: 'req-public-page-clarification',
userMessage: {
role: 'user',
content: [{ type: 'text', text: '【TKMind 路由提示】使用 static-page-publish\n帮我生成一个页面吧' }],
metadata: { displayText: '帮我生成一个页面吧' },
},
});
await waitFor(() => pool.runs.get(run.id)?.status === 'succeeded');
assert.equal(pool.runs.get(run.id).error_message, null);
});
test('Page Data run succeeds only after a generated session page is detected', async () => {
const pool = createFakePool({
sessionDeliverables: {
+20
View File
@@ -108,6 +108,26 @@ export function isPageGenerationIntent(text) {
return PAGE_GENERATION_INTENT_PATTERNS.some((pattern) => pattern.test(normalized));
}
const GENERIC_PAGE_REQUEST_FILLER_RE =
/(?:请|麻烦|能否|可以|可不可以|帮我|给我|我想要?|想要|生成|做|制作|创建|设计|写|出|一个|一份|个|页面|网页|H5|HTML|活动页|宣传页|落地页|分享页|吧|呢|好吗|谢谢)/giu;
const GENERIC_PAGE_REQUEST_ENGLISH_FILLER_RE =
/\b(?:please|can|could|would|you|help|me|i|want|to|publish|create|generate|make|build|design|a|an|one|html|web|page|landing|h5|thanks?)\b/giu;
/**
* A bare request such as “帮我生成一个页面吧” names no subject or content.
* It is a valid page intent, but the current turn can only clarify requirements;
* the delivery guard must not require public HTML until the user supplies details.
*/
export function isGenericPageGenerationRequest(text) {
const normalized = String(text ?? '').trim();
if (!normalized || !isPageGenerationIntent(normalized)) return false;
const remainder = normalized
.replace(GENERIC_PAGE_REQUEST_FILLER_RE, '')
.replace(GENERIC_PAGE_REQUEST_ENGLISH_FILLER_RE, '')
.replace(/[\s,。!?、,.!?;:'"“”‘’()()[\]{}_-]+/gu, '');
return remainder.length === 0;
}
export function isProductCampaignIntent(text) {
const normalized = String(text ?? '').trim();
if (!normalized) return false;
+9
View File
@@ -9,6 +9,7 @@ import {
isPageDataDevIntent,
isPageDataIntent,
isPageGenerationIntent,
isGenericPageGenerationRequest,
} from './chat-skills.mjs';
test('filterChatSkills shows summarize and analyze without granted skills', () => {
@@ -125,6 +126,14 @@ test('isPageGenerationIntent matches implicit travel guide page requests', () =>
assert.equal(isPageGenerationIntent('你好'), false);
});
test('isGenericPageGenerationRequest only matches page requests without a subject', () => {
assert.equal(isGenericPageGenerationRequest('帮我生成一个页面吧'), true);
assert.equal(isGenericPageGenerationRequest('Please create a web page'), true);
assert.equal(isGenericPageGenerationRequest('帮我做一个秋夜诗的 H5 页面'), false);
assert.equal(isGenericPageGenerationRequest('苏州攻略页面'), false);
assert.equal(isGenericPageGenerationRequest('你好'), false);
});
test('buildAutoChatSkillPrefix prefers page-data-collect for survey requests', () => {
const text = '帮我在这个页面增加一个调查问卷,出三个问题,密码 888 查看提交记录';
const prefix = buildAutoChatSkillPrefix(text, ['page-data-collect', 'static-page-publish']);
@@ -50,6 +50,31 @@
---
## 3. 页面需求澄清:禁止误报“未生成 public HTML”
### 症状
- 用户只说「帮我生成一个页面吧」,没有给出主题或内容
- 助手正常追问页面类型、主题或素材
- Finish 后却显示红色错误条:「页面任务未生成 public HTML 交付物,不能标记成功」
### 根因与必须保留
`agent-run-gateway.mjs` 的页面交付守卫曾把所有页面意图都视为本轮必须交付 HTML,
没有区分“信息足够、可执行的页面任务”和“只能先澄清的泛化请求”。
- 必须使用用户消息 `metadata.displayText` 判断请求本身,不能让内部 routing / skill 前缀影响判定
- 「帮我生成一个页面吧」这类没有主题的泛化请求允许以澄清回复正常结束
- 「帮我做一个秋夜诗 H5 页面」等已有主题的任务仍须 fail closed:没有本轮 `public/*.html` 就不能标记成功
- Page Data 任务的交付守卫不受此例外影响
### 守卫
- 单测:`chat-skills.test.mjs``agent-run-gateway.test.mjs`
- 综合验证:`npm run verify:h5-session-patches`
---
## 发版 / CI 必跑命令
```bash