import { buildCodeRunCompletionReply } from './agent-run-gateway.mjs'; import { enforcePageGenerationCursorRuntime } from './cursor-page-routing.mjs'; const DEFAULT_POLL_MS = 2000; function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } function buildWechatCursorUserMessage({ displayText, intentKind, channel = 'wechat_mp', }) { const taskText = String(displayText ?? '').trim(); return { role: 'user', content: [{ type: 'text', text: taskText }], metadata: { displayText: taskText, memindRun: { 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, }, }, }; } async function readCursorCompletionText(agentRunGateway, userId, runId) { const eventsResult = await agentRunGateway.listRunEventsForUser(userId, runId, { limit: 200 }); const events = Array.isArray(eventsResult?.events) ? eventsResult.events : []; const resultEvent = [...events].reverse().find((item) => item.eventType === 'tool_gateway_result'); if (!resultEvent?.data) { return buildCodeRunCompletionReply({ executor: 'cursor', stdout: '' }); } return buildCodeRunCompletionReply({ executor: resultEvent.data.executor ?? 'cursor', stdout: resultEvent.data.stdoutTail ?? '', }); } 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, sessionId = null, requestId, displayText, agentPrompt, intentKind = 'page.generate', policy = null, timeoutMs = 15 * 60 * 1000, pollMs = DEFAULT_POLL_MS, logger = console, } = {}) { return executeCursorChannelCodeRun({ agentRunGateway, userId, sessionId, requestId, displayText, agentPrompt, intentKind, channel: 'wechat_mp', taskType: 'wechat_page_generate', policy, timeoutMs, pollMs, logger, }); }