fix(scheduled-task): release page delivery contracts before notifying users
Memind CI / Test, build, and release guards (push) Successful in 3m36s
Memind CI / Test, build, and release guards (push) Successful in 3m36s
Scheduled automation now prepares and retries MindSpace delivery contracts, blocks WeChat pushes when public HTML links are not ready, and reconciles stuck static preparing contracts on each worker scan. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,10 +1,18 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs/promises';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
buildScheduledTaskExecutionPrompt,
|
||||
deliveryTextPromisesPublicHtml,
|
||||
extractPublicHtmlPathsFromText,
|
||||
extractScheduledTaskDeliveryText,
|
||||
finalizeScheduledTaskPageDelivery,
|
||||
formatScheduledTaskDeliveryMessage,
|
||||
looksLikeScheduledTaskNonDelivery,
|
||||
reconcileStuckStaticPageDeliveryContracts,
|
||||
resolveScheduledTaskDeliveryRetryDelaysMs,
|
||||
} from './scheduled-task-executor.mjs';
|
||||
|
||||
test('buildScheduledTaskExecutionPrompt includes task spec and automation marker', () => {
|
||||
@@ -32,6 +40,12 @@ test('looksLikeScheduledTaskNonDelivery detects clarification replies', () => {
|
||||
looksLikeScheduledTaskNonDelivery('页面已生成:https://example.com/news.html'),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
looksLikeScheduledTaskNonDelivery(
|
||||
'页面已生成:https://m.tkmind.cn/MindSpace/user-1/public/daily-news.html',
|
||||
),
|
||||
true,
|
||||
);
|
||||
assert.equal(
|
||||
looksLikeScheduledTaskNonDelivery('好的', { readyPaths: ['public/news.html'] }),
|
||||
false,
|
||||
@@ -41,6 +55,91 @@ test('looksLikeScheduledTaskNonDelivery detects clarification replies', () => {
|
||||
assert.equal(looksLikeScheduledTaskNonDelivery('好的'), true);
|
||||
});
|
||||
|
||||
test('extractPublicHtmlPathsFromText parses MindSpace public links', () => {
|
||||
assert.deepEqual(
|
||||
extractPublicHtmlPathsFromText(
|
||||
'链接:https://m.tkmind.cn/MindSpace/u/public/daily-news-0816.html',
|
||||
),
|
||||
['public/daily-news-0816.html'],
|
||||
);
|
||||
});
|
||||
|
||||
test('deliveryTextPromisesPublicHtml detects page delivery replies', () => {
|
||||
assert.equal(
|
||||
deliveryTextPromisesPublicHtml('今日摘要:天气不错'),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
deliveryTextPromisesPublicHtml('public/daily-news.html 已生成'),
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveScheduledTaskDeliveryRetryDelaysMs reads env override', () => {
|
||||
assert.deepEqual(
|
||||
resolveScheduledTaskDeliveryRetryDelaysMs({
|
||||
H5_SCHEDULED_TASK_DELIVERY_RETRY_DELAYS_MS: '0,100,250',
|
||||
}),
|
||||
[0, 100, 250],
|
||||
);
|
||||
});
|
||||
|
||||
test('finalizeScheduledTaskPageDelivery prepares and releases static contracts', async () => {
|
||||
const calls = [];
|
||||
const pool = {
|
||||
async query(sql, params) {
|
||||
calls.push({ sql, params });
|
||||
if (sql.includes('FROM h5_page_delivery_contracts')) {
|
||||
return [[{ workspace_relative_path: 'public/news.html' }]];
|
||||
}
|
||||
if (sql.includes('SELECT id, data_mode, status')) {
|
||||
return [[{ id: 'c1', data_mode: 'static', status: 'preparing' }]];
|
||||
}
|
||||
if (sql.includes("SET status = 'ready'")) {
|
||||
return [{ affectedRows: 1 }];
|
||||
}
|
||||
return [[]];
|
||||
},
|
||||
};
|
||||
const readyPaths = await finalizeScheduledTaskPageDelivery({
|
||||
pool,
|
||||
userId: 'user-1',
|
||||
sessionId: 'session-1',
|
||||
messages: [],
|
||||
publishDir: '/tmp/publish',
|
||||
deliveryText: 'public/news.html 已生成',
|
||||
logger: { warn() {}, info() {} },
|
||||
});
|
||||
assert.deepEqual(readyPaths, ['public/news.html']);
|
||||
assert.ok(calls.some((call) => call.sql.includes('INSERT INTO h5_page_delivery_contracts')));
|
||||
});
|
||||
|
||||
test('reconcileStuckStaticPageDeliveryContracts releases materialized static pages', async () => {
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'scheduled-task-'));
|
||||
const userId = 'user-1';
|
||||
const relativePath = 'public/news.html';
|
||||
const filePath = path.join(dir, 'MindSpace', userId, relativePath);
|
||||
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
||||
await fs.writeFile(filePath, '<html></html>', 'utf8');
|
||||
const pool = {
|
||||
async query(sql) {
|
||||
if (sql.includes('FROM h5_page_delivery_contracts')) {
|
||||
return [[{ user_id: userId, workspace_relative_path: relativePath }]];
|
||||
}
|
||||
if (sql.includes("SET status = 'ready'")) {
|
||||
return [{ affectedRows: 1 }];
|
||||
}
|
||||
return [[]];
|
||||
},
|
||||
};
|
||||
const released = await reconcileStuckStaticPageDeliveryContracts({
|
||||
pool,
|
||||
h5Root: dir,
|
||||
logger: { info() {} },
|
||||
});
|
||||
assert.deepEqual(released, [relativePath]);
|
||||
});
|
||||
|
||||
test('extractScheduledTaskDeliveryText reads last assistant message', () => {
|
||||
const text = extractScheduledTaskDeliveryText([
|
||||
{ role: 'user', content: [{ type: 'text', text: 'hi' }] },
|
||||
|
||||
Reference in New Issue
Block a user