Fix scheduled task page delivery unlock and notification links.
Memind CI / Test, build, and release guards (push) Failing after 5s
Memind CI / Test, build, and release guards (push) Failing after 5s
Finalize page delivery contracts after worker execution, fetch session messages via tkmindProxy, and append public page URLs to WeChat notifications. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
import crypto from 'node:crypto';
|
import crypto from 'node:crypto';
|
||||||
|
import path from 'node:path';
|
||||||
import { buildChatSkillPrompt, SCHEDULED_TASK_AUTOMATION_SKILL_NAME } from './chat-skills.mjs';
|
import { buildChatSkillPrompt, SCHEDULED_TASK_AUTOMATION_SKILL_NAME } from './chat-skills.mjs';
|
||||||
|
import { markPageDeliveryContractReady } from './mindspace-delivery-contract.mjs';
|
||||||
|
import {
|
||||||
|
collectOwnPublicHtmlRelativePaths,
|
||||||
|
materializeMissingPublicHtmlWrites,
|
||||||
|
} from './mindspace-public-finish-sync.mjs';
|
||||||
import { localDateLabel } from './schedule-time.mjs';
|
import { localDateLabel } from './schedule-time.mjs';
|
||||||
|
|
||||||
function messageText(message) {
|
function messageText(message) {
|
||||||
@@ -63,10 +69,65 @@ export function formatScheduledTaskDeliveryMessage(task, deliveryText) {
|
|||||||
return `${header}\n\n${body}`.trim();
|
return `${header}\n\n${body}`.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function finalizeScheduledTaskPageDelivery({
|
||||||
|
pool,
|
||||||
|
userId,
|
||||||
|
sessionId,
|
||||||
|
messages,
|
||||||
|
publishDir,
|
||||||
|
currentUser = null,
|
||||||
|
logger = console,
|
||||||
|
} = {}) {
|
||||||
|
if (!pool || !userId || !publishDir) return [];
|
||||||
|
|
||||||
|
const materialized = materializeMissingPublicHtmlWrites({ messages, publishDir });
|
||||||
|
const relativePaths = new Set(
|
||||||
|
collectOwnPublicHtmlRelativePaths({
|
||||||
|
messages,
|
||||||
|
currentUser: currentUser ?? { id: userId },
|
||||||
|
publishDir,
|
||||||
|
materialized: materialized.materialized,
|
||||||
|
skipped: materialized.skipped,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sessionId) {
|
||||||
|
const [rows] = await pool.query(
|
||||||
|
`SELECT workspace_relative_path
|
||||||
|
FROM h5_page_delivery_contracts
|
||||||
|
WHERE user_id = ? AND request_id = ? AND status = 'preparing'`,
|
||||||
|
[userId, sessionId],
|
||||||
|
);
|
||||||
|
for (const row of rows ?? []) {
|
||||||
|
if (row?.workspace_relative_path) relativePaths.add(row.workspace_relative_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const readyPaths = [];
|
||||||
|
for (const relativePath of relativePaths) {
|
||||||
|
const ready = await markPageDeliveryContractReady({
|
||||||
|
pool,
|
||||||
|
userId,
|
||||||
|
relativePath,
|
||||||
|
}).catch(() => false);
|
||||||
|
if (ready) readyPaths.push(relativePath);
|
||||||
|
else {
|
||||||
|
logger.warn?.('[ScheduledTask] delivery contract not ready', {
|
||||||
|
userId,
|
||||||
|
sessionId,
|
||||||
|
relativePath,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return readyPaths;
|
||||||
|
}
|
||||||
|
|
||||||
export async function executeScheduledTask(task, {
|
export async function executeScheduledTask(task, {
|
||||||
userAuth,
|
userAuth,
|
||||||
tkmindProxy,
|
tkmindProxy,
|
||||||
sessionSnapshotService = null,
|
sessionSnapshotService = null,
|
||||||
|
pool = null,
|
||||||
|
h5Root = null,
|
||||||
timeoutMs = 15 * 60 * 1000,
|
timeoutMs = 15 * 60 * 1000,
|
||||||
logger = console,
|
logger = console,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
@@ -113,19 +174,45 @@ export async function executeScheduledTask(task, {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let messages = [];
|
let messages = [];
|
||||||
if (typeof sessionSnapshotService?.refresh === 'function') {
|
if (typeof tkmindProxy.fetchSessionConversationForUser === 'function') {
|
||||||
const refreshed = await sessionSnapshotService.refresh(sessionId).catch(() => null);
|
messages = await tkmindProxy.fetchSessionConversationForUser(task.userId, sessionId).catch(() => []);
|
||||||
messages = refreshed?.messages ?? refreshed?.conversation?.messages ?? [];
|
|
||||||
} else if (typeof sessionSnapshotService?.get === 'function') {
|
} else if (typeof sessionSnapshotService?.get === 'function') {
|
||||||
const snapshot = await sessionSnapshotService.get(sessionId).catch(() => null);
|
const snapshot = await sessionSnapshotService.get(sessionId).catch(() => null);
|
||||||
messages = snapshot?.messages ?? snapshot?.conversation?.messages ?? [];
|
messages = snapshot?.messages ?? snapshot?.conversation?.messages ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const deliveryText = extractScheduledTaskDeliveryText(messages, task);
|
const publishDir = h5Root && task.userId
|
||||||
|
? path.join(h5Root, 'MindSpace', task.userId)
|
||||||
|
: null;
|
||||||
|
const readyPaths = await finalizeScheduledTaskPageDelivery({
|
||||||
|
pool,
|
||||||
|
userId: task.userId,
|
||||||
|
sessionId,
|
||||||
|
messages,
|
||||||
|
publishDir,
|
||||||
|
logger,
|
||||||
|
}).catch((error) => {
|
||||||
|
logger.warn?.('[ScheduledTask] finalize page delivery failed:', error);
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
|
let deliveryText = extractScheduledTaskDeliveryText(messages, task);
|
||||||
|
if (
|
||||||
|
readyPaths.length > 0
|
||||||
|
&& !/https?:\/\//i.test(deliveryText)
|
||||||
|
&& task.userId
|
||||||
|
) {
|
||||||
|
const links = readyPaths.map(
|
||||||
|
(relativePath) => `https://m.tkmind.cn/MindSpace/${task.userId}/${relativePath}`,
|
||||||
|
);
|
||||||
|
deliveryText = `${deliveryText}\n\n页面链接:\n${links.join('\n')}`.trim();
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sessionId,
|
sessionId,
|
||||||
requestId,
|
requestId,
|
||||||
deliveryText,
|
deliveryText,
|
||||||
messages,
|
messages,
|
||||||
|
readyPaths,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ export function startScheduledTaskWorker({
|
|||||||
tkmindProxy = null,
|
tkmindProxy = null,
|
||||||
sessionSnapshotService = null,
|
sessionSnapshotService = null,
|
||||||
notificationDispatcher = null,
|
notificationDispatcher = null,
|
||||||
|
pool = null,
|
||||||
|
h5Root = null,
|
||||||
logger = console,
|
logger = console,
|
||||||
intervalMs = Number(process.env.H5_SCHEDULED_TASK_SCAN_INTERVAL_MS ?? 30_000),
|
intervalMs = Number(process.env.H5_SCHEDULED_TASK_SCAN_INTERVAL_MS ?? 30_000),
|
||||||
maxAttempts = Number(process.env.H5_SCHEDULED_TASK_MAX_ATTEMPTS ?? 3),
|
maxAttempts = Number(process.env.H5_SCHEDULED_TASK_MAX_ATTEMPTS ?? 3),
|
||||||
@@ -70,6 +72,8 @@ export function startScheduledTaskWorker({
|
|||||||
userAuth,
|
userAuth,
|
||||||
tkmindProxy,
|
tkmindProxy,
|
||||||
sessionSnapshotService,
|
sessionSnapshotService,
|
||||||
|
pool,
|
||||||
|
h5Root,
|
||||||
timeoutMs: executionTimeoutMs,
|
timeoutMs: executionTimeoutMs,
|
||||||
logger,
|
logger,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -286,6 +286,8 @@ export async function bootstrapPortalIntegrationServices({
|
|||||||
tkmindProxy,
|
tkmindProxy,
|
||||||
sessionSnapshotService,
|
sessionSnapshotService,
|
||||||
notificationDispatcher,
|
notificationDispatcher,
|
||||||
|
pool,
|
||||||
|
h5Root,
|
||||||
logger,
|
logger,
|
||||||
});
|
});
|
||||||
logger.log('Scheduled task worker enabled');
|
logger.log('Scheduled task worker enabled');
|
||||||
|
|||||||
Reference in New Issue
Block a user