Add per-feature Cursor channel toggles for admin and runtime.
Memind CI / Test, build, and release guards (push) Has been cancelled
Memind CI / Test, build, and release guards (push) Has been cancelled
Expose page/data/scheduled-task/chat-bridge switches in the智趣体验通道 config so Tang can roll out Cursor paths independently with DeepSeek fallback. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+134
-61
@@ -10,6 +10,7 @@ function sleep(ms) {
|
||||
function buildWechatCursorUserMessage({
|
||||
displayText,
|
||||
intentKind,
|
||||
channel = 'wechat_mp',
|
||||
}) {
|
||||
const taskText = String(displayText ?? '').trim();
|
||||
return {
|
||||
@@ -18,9 +19,9 @@ function buildWechatCursorUserMessage({
|
||||
metadata: {
|
||||
displayText: taskText,
|
||||
memindRun: {
|
||||
channel: 'wechat_mp',
|
||||
wechatCursorChannel: true,
|
||||
taskType: 'wechat_page_generate',
|
||||
channel,
|
||||
wechatCursorChannel: channel === 'wechat_mp',
|
||||
taskType: channel === 'wechat_mp' ? 'wechat_page_generate' : 'h5_chat_code_task',
|
||||
toolMode: 'code',
|
||||
requiredExecutor: 'cursor',
|
||||
intentKind: String(intentKind ?? '').trim() || null,
|
||||
@@ -42,6 +43,123 @@ async function readCursorCompletionText(agentRunGateway, userId, runId) {
|
||||
});
|
||||
}
|
||||
|
||||
export async function executeCursorChannelCodeRun({
|
||||
agentRunGateway,
|
||||
userId,
|
||||
sessionId = null,
|
||||
requestId,
|
||||
displayText,
|
||||
agentPrompt = null,
|
||||
intentKind = 'page.generate',
|
||||
channel = 'wechat_mp',
|
||||
taskType = null,
|
||||
policy = null,
|
||||
forceCursorExecutor = false,
|
||||
timeoutMs = 15 * 60 * 1000,
|
||||
pollMs = DEFAULT_POLL_MS,
|
||||
logger = console,
|
||||
} = {}) {
|
||||
if (!agentRunGateway?.createRun || !agentRunGateway?.dispatchRun || !agentRunGateway?.getRunForUser) {
|
||||
throw Object.assign(new Error('Cursor 执行网关不可用'), {
|
||||
code: 'CURSOR_CHANNEL_GATEWAY_UNAVAILABLE',
|
||||
});
|
||||
}
|
||||
|
||||
const promptText = String(agentPrompt ?? displayText ?? '').trim();
|
||||
let userMessage = buildWechatCursorUserMessage({
|
||||
displayText: String(displayText ?? promptText).trim(),
|
||||
intentKind,
|
||||
channel,
|
||||
});
|
||||
if (promptText) {
|
||||
userMessage = {
|
||||
...userMessage,
|
||||
content: [{ type: 'text', text: promptText }],
|
||||
};
|
||||
}
|
||||
|
||||
const resolvedTaskType = taskType
|
||||
?? (channel === 'wechat_mp' ? 'wechat_page_generate' : 'h5_chat_code_task');
|
||||
let cursorRuntime = enforcePageGenerationCursorRuntime(userMessage, {
|
||||
rawToolMode: 'code',
|
||||
taskType: resolvedTaskType,
|
||||
env: process.env,
|
||||
channelEligible: true,
|
||||
policy,
|
||||
});
|
||||
if (forceCursorExecutor && !cursorRuntime.requiredExecutor) {
|
||||
cursorRuntime = {
|
||||
...cursorRuntime,
|
||||
rawToolMode: 'code',
|
||||
taskType: resolvedTaskType,
|
||||
requiredExecutor: 'cursor',
|
||||
};
|
||||
userMessage = {
|
||||
...userMessage,
|
||||
metadata: {
|
||||
...(userMessage.metadata ?? {}),
|
||||
memindRun: {
|
||||
...(userMessage.metadata?.memindRun ?? {}),
|
||||
requiredExecutor: 'cursor',
|
||||
executor: 'cursor',
|
||||
toolMode: 'code',
|
||||
},
|
||||
},
|
||||
};
|
||||
} else {
|
||||
userMessage = cursorRuntime.userMessage;
|
||||
}
|
||||
|
||||
const run = await agentRunGateway.createRun(userId, {
|
||||
sessionId,
|
||||
requestId,
|
||||
userMessage,
|
||||
toolMode: 'code',
|
||||
taskType: cursorRuntime.taskType ?? resolvedTaskType,
|
||||
});
|
||||
agentRunGateway.dispatchRun(run.id);
|
||||
|
||||
const deadline = Date.now() + Math.max(0, Number(timeoutMs) || 0);
|
||||
while (Date.now() <= deadline) {
|
||||
const latest = await agentRunGateway.getRunForUser(userId, run.id);
|
||||
if (!latest) {
|
||||
throw Object.assign(new Error('Cursor 任务丢失'), {
|
||||
code: 'CURSOR_CHANNEL_RUN_MISSING',
|
||||
});
|
||||
}
|
||||
if (latest.status === 'succeeded') {
|
||||
const text = await readCursorCompletionText(agentRunGateway, userId, run.id);
|
||||
logger.info?.('[cursor-channel] run succeeded', {
|
||||
userId,
|
||||
runId: run.id,
|
||||
requestId,
|
||||
channel,
|
||||
});
|
||||
return {
|
||||
text,
|
||||
runId: run.id,
|
||||
tokenState: null,
|
||||
messages: [{
|
||||
role: 'assistant',
|
||||
content: [{ type: 'text', text }],
|
||||
metadata: { userVisible: true, source: 'cursor-channel-agent-run', channel },
|
||||
}],
|
||||
requestMessages: [],
|
||||
};
|
||||
}
|
||||
if (latest.status === 'failed') {
|
||||
const error = new Error(latest.error || 'Cursor 执行失败');
|
||||
error.code = 'CURSOR_CHANNEL_RUN_FAILED';
|
||||
throw error;
|
||||
}
|
||||
await sleep(Math.max(500, Number(pollMs) || DEFAULT_POLL_MS));
|
||||
}
|
||||
|
||||
throw Object.assign(new Error('Cursor 执行超时'), {
|
||||
code: 'CURSOR_CHANNEL_RUN_TIMEOUT',
|
||||
});
|
||||
}
|
||||
|
||||
export async function executeWechatCursorAgentRun({
|
||||
agentRunGateway,
|
||||
userId,
|
||||
@@ -50,69 +168,24 @@ export async function executeWechatCursorAgentRun({
|
||||
displayText,
|
||||
agentPrompt,
|
||||
intentKind = 'page.generate',
|
||||
policy = null,
|
||||
timeoutMs = 15 * 60 * 1000,
|
||||
pollMs = DEFAULT_POLL_MS,
|
||||
logger = console,
|
||||
} = {}) {
|
||||
if (!agentRunGateway?.createRun || !agentRunGateway?.dispatchRun || !agentRunGateway?.getRunForUser) {
|
||||
throw Object.assign(new Error('WeChat Cursor 执行网关不可用'), {
|
||||
code: 'WECHAT_CURSOR_GATEWAY_UNAVAILABLE',
|
||||
});
|
||||
}
|
||||
|
||||
let userMessage = buildWechatCursorUserMessage({ displayText, intentKind });
|
||||
const cursorRuntime = enforcePageGenerationCursorRuntime(userMessage, {
|
||||
rawToolMode: 'code',
|
||||
taskType: 'wechat_page_generate',
|
||||
env: process.env,
|
||||
channelEligible: true,
|
||||
});
|
||||
userMessage = cursorRuntime.userMessage;
|
||||
|
||||
const run = await agentRunGateway.createRun(userId, {
|
||||
return executeCursorChannelCodeRun({
|
||||
agentRunGateway,
|
||||
userId,
|
||||
sessionId,
|
||||
requestId,
|
||||
userMessage,
|
||||
toolMode: 'code',
|
||||
taskType: cursorRuntime.taskType ?? 'h5_chat_code_task',
|
||||
});
|
||||
agentRunGateway.dispatchRun(run.id);
|
||||
|
||||
const deadline = Date.now() + Math.max(0, Number(timeoutMs) || 0);
|
||||
while (Date.now() <= deadline) {
|
||||
const latest = await agentRunGateway.getRunForUser(userId, run.id);
|
||||
if (!latest) {
|
||||
throw Object.assign(new Error('WeChat Cursor 任务丢失'), {
|
||||
code: 'WECHAT_CURSOR_RUN_MISSING',
|
||||
});
|
||||
}
|
||||
if (latest.status === 'succeeded') {
|
||||
const text = await readCursorCompletionText(agentRunGateway, userId, run.id);
|
||||
logger.info?.('[wechat-cursor] run succeeded', {
|
||||
userId,
|
||||
runId: run.id,
|
||||
requestId,
|
||||
});
|
||||
return {
|
||||
text,
|
||||
tokenState: null,
|
||||
messages: [{
|
||||
role: 'assistant',
|
||||
content: [{ type: 'text', text }],
|
||||
metadata: { userVisible: true, source: 'wechat-cursor-agent-run' },
|
||||
}],
|
||||
requestMessages: [],
|
||||
};
|
||||
}
|
||||
if (latest.status === 'failed') {
|
||||
const error = new Error(latest.error || 'WeChat Cursor 执行失败');
|
||||
error.code = 'WECHAT_CURSOR_RUN_FAILED';
|
||||
throw error;
|
||||
}
|
||||
await sleep(Math.max(500, Number(pollMs) || DEFAULT_POLL_MS));
|
||||
}
|
||||
|
||||
throw Object.assign(new Error('WeChat Cursor 执行超时'), {
|
||||
code: 'WECHAT_CURSOR_RUN_TIMEOUT',
|
||||
displayText,
|
||||
agentPrompt,
|
||||
intentKind,
|
||||
channel: 'wechat_mp',
|
||||
taskType: 'wechat_page_generate',
|
||||
policy,
|
||||
timeoutMs,
|
||||
pollMs,
|
||||
logger,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user