fix(agent-run): align cursor executor path with 103 production hotfixes
Recover requiredExecutor fallback, direct cursor launch in tool gateway, and user-facing brand sanitization in source so the next portal release can replace manual bundled edits on 103. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+54
-16
@@ -2,8 +2,22 @@ import { spawn as nodeSpawn } from 'node:child_process';
|
||||
import { EventEmitter } from 'node:events';
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { buildCursorExecutorLaunchPlan } from './cursor-agent-launch.mjs';
|
||||
import { resolveExecutorDisplayLabel } from './executor-display-label.mjs';
|
||||
|
||||
const CODE_EXECUTORS = new Set(['aider', 'openhands']);
|
||||
const BASE_CODE_EXECUTORS = ['aider', 'openhands'];
|
||||
|
||||
function cursorExecutorEnabled(env = process.env) {
|
||||
const raw = String(env.MEMIND_CURSOR_EXECUTOR_ENABLED ?? '').trim().toLowerCase();
|
||||
if (!raw) return false;
|
||||
return ['1', 'true', 'yes', 'on'].includes(raw);
|
||||
}
|
||||
|
||||
function codeExecutorsForEnv(env = process.env) {
|
||||
return cursorExecutorEnabled(env)
|
||||
? ['cursor', ...BASE_CODE_EXECUTORS]
|
||||
: [...BASE_CODE_EXECUTORS];
|
||||
}
|
||||
const DEFAULT_STDIO_LIMIT = 64 * 1024;
|
||||
|
||||
function envFlag(value, fallback = false) {
|
||||
@@ -18,9 +32,10 @@ function positiveInteger(value, fallback) {
|
||||
return Math.floor(n);
|
||||
}
|
||||
|
||||
function normalizeExecutor(value, fallback = 'aider') {
|
||||
function normalizeExecutor(value, fallback = 'aider', env = process.env) {
|
||||
const normalized = String(value ?? fallback).trim().toLowerCase();
|
||||
if (CODE_EXECUTORS.has(normalized)) return normalized;
|
||||
const allowed = new Set(codeExecutorsForEnv(env));
|
||||
if (allowed.has(normalized)) return normalized;
|
||||
return fallback;
|
||||
}
|
||||
|
||||
@@ -150,7 +165,12 @@ export function createToolGateway({
|
||||
} = {}) {
|
||||
const enabled = envFlag(env.MEMIND_TOOL_GATEWAY_ENABLED, false);
|
||||
const dryRun = envFlag(env.MEMIND_TOOL_GATEWAY_DRY_RUN, false);
|
||||
const defaultExecutor = normalizeExecutor(env.MEMIND_TOOL_GATEWAY_DEFAULT_EXECUTOR, 'aider');
|
||||
const cursorEnabled = cursorExecutorEnabled(env);
|
||||
const defaultExecutor = normalizeExecutor(env.MEMIND_TOOL_GATEWAY_DEFAULT_EXECUTOR, 'aider', env);
|
||||
const cursorTaskTypes = csvSet(
|
||||
env.MEMIND_TOOL_GATEWAY_CURSOR_TASK_TYPES
|
||||
?? 'h5_chat_code_task,mindspace_page,mindspace_html_page',
|
||||
);
|
||||
const openhandsTaskTypes = csvSet(
|
||||
env.MEMIND_TOOL_GATEWAY_OPENHANDS_TASK_TYPES
|
||||
?? 'repo_refactor,multi_file,complex_repo,page_data_dev_complex',
|
||||
@@ -162,8 +182,10 @@ export function createToolGateway({
|
||||
enabled,
|
||||
dryRun,
|
||||
protocol: 'agent-run-v1',
|
||||
executors: ['aider', 'openhands'],
|
||||
executors: codeExecutorsForEnv(env),
|
||||
defaultExecutor,
|
||||
cursorEnabled,
|
||||
cursorTaskTypes: [...cursorTaskTypes],
|
||||
openhandsTaskTypes: [...openhandsTaskTypes],
|
||||
};
|
||||
}
|
||||
@@ -171,9 +193,14 @@ export function createToolGateway({
|
||||
function selectExecutor({ userMessage, taskType } = {}) {
|
||||
const metadata = userMessage?.metadata ?? {};
|
||||
const runMetadata = metadata.memindRun ?? metadata.agentRun ?? {};
|
||||
const requested = normalizeExecutor(runMetadata.executor, '');
|
||||
const requested = normalizeExecutor(
|
||||
runMetadata.executor || runMetadata.requiredExecutor,
|
||||
'',
|
||||
env,
|
||||
);
|
||||
if (requested) return requested;
|
||||
const normalizedTaskType = String(taskType ?? runMetadata.taskType ?? '').trim().toLowerCase();
|
||||
if (cursorEnabled && cursorTaskTypes.has(normalizedTaskType)) return 'cursor';
|
||||
if (openhandsTaskTypes.has(normalizedTaskType)) return 'openhands';
|
||||
return defaultExecutor;
|
||||
}
|
||||
@@ -190,9 +217,6 @@ export function createToolGateway({
|
||||
if (!enabled) {
|
||||
throw new Error('Tool Gateway is disabled');
|
||||
}
|
||||
if (!llmProviderService?.getExecutorLaunchPlan) {
|
||||
throw new Error('Tool Gateway missing llm provider service');
|
||||
}
|
||||
const instruction = extractToolInstruction(userMessage);
|
||||
if (!instruction) {
|
||||
throw new Error('Tool Gateway job missing instruction');
|
||||
@@ -204,13 +228,25 @@ export function createToolGateway({
|
||||
const executorInstruction = receiptPath
|
||||
? `${instruction}\n\nThe validation receipt is already included in the Aider chat. Edit it directly; do not ask the user to add it.`
|
||||
: instruction;
|
||||
let plan = await llmProviderService.getExecutorLaunchPlan(executor, {
|
||||
cwd,
|
||||
mode: 'headless',
|
||||
instruction: executorInstruction,
|
||||
purpose: 'default',
|
||||
includeSecret: true,
|
||||
});
|
||||
let plan;
|
||||
if (executor === 'cursor') {
|
||||
plan = buildCursorExecutorLaunchPlan({
|
||||
cwd,
|
||||
instruction: executorInstruction,
|
||||
env,
|
||||
});
|
||||
} else {
|
||||
if (!llmProviderService?.getExecutorLaunchPlan) {
|
||||
throw new Error('Tool Gateway missing llm provider service');
|
||||
}
|
||||
plan = await llmProviderService.getExecutorLaunchPlan(executor, {
|
||||
cwd,
|
||||
mode: 'headless',
|
||||
instruction: executorInstruction,
|
||||
purpose: 'default',
|
||||
includeSecret: true,
|
||||
});
|
||||
}
|
||||
if (!plan?.ok) {
|
||||
throw new Error(plan?.message ?? `Tool Gateway launch plan unavailable for ${executor}`);
|
||||
}
|
||||
@@ -226,6 +262,7 @@ export function createToolGateway({
|
||||
ok: true,
|
||||
dryRun: true,
|
||||
executor,
|
||||
executorLabel: resolveExecutorDisplayLabel(executor, plan.executorLabel),
|
||||
protocol: 'agent-run-v1',
|
||||
cwd: plan.cwd,
|
||||
command: plan.command,
|
||||
@@ -274,6 +311,7 @@ export function createToolGateway({
|
||||
resolve({
|
||||
ok: true,
|
||||
executor,
|
||||
executorLabel: resolveExecutorDisplayLabel(executor, plan.executorLabel),
|
||||
protocol: 'agent-run-v1',
|
||||
cwd: plan.cwd,
|
||||
command: plan.command,
|
||||
|
||||
Reference in New Issue
Block a user