Files
memind/tool-gateway.test.mjs
T
john fc4ac98e9f feat(context): add dsh executor and headroom active loopback probe
Wire DeepSeek Harness as an optional fourth code executor (default off)
and add a loopback observation script that compares prompt tokens through
headroom proxy with OPENAI_TARGET_API_URL pointed at the compat proxy.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 21:32:57 +08:00

278 lines
8.4 KiB
JavaScript

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 {
createToolGateway,
extractToolInstruction,
hardenAiderLaunchPlan,
prepareAiderReceiptFile,
resolveAiderReceiptPath,
} from './tool-gateway.mjs';
test('tool gateway extracts text instructions from H5 message content', () => {
assert.equal(
extractToolInstruction({
content: [
{ type: 'text', text: '第一步' },
{ type: 'image_url', image_url: { url: 'https://example.test/a.png' } },
{ type: 'text', text: '第二步' },
],
}),
'第一步\n第二步',
);
});
test('tool gateway is disabled by default and reports protocol', () => {
const gateway = createToolGateway({ env: {} });
assert.deepEqual(gateway.getStatus(), {
enabled: false,
dryRun: false,
protocol: 'agent-run-v1',
executors: ['aider', 'openhands'],
defaultExecutor: 'aider',
cursorEnabled: false,
dshEnabled: false,
cursorTaskTypes: ['h5_chat_code_task', 'mindspace_page', 'mindspace_html_page'],
dshTaskTypes: ['repo_refactor', 'multi_file'],
openhandsTaskTypes: ['repo_refactor', 'multi_file', 'complex_repo', 'page_data_dev_complex'],
});
});
test('tool gateway exposes cursor executor when enabled', () => {
const gateway = createToolGateway({
env: {
MEMIND_CURSOR_EXECUTOR_ENABLED: '1',
MEMIND_TOOL_GATEWAY_CURSOR_TASK_TYPES: 'h5_chat_code_task',
},
});
assert.deepEqual(gateway.getStatus().executors, ['cursor', 'aider', 'openhands']);
assert.equal(
gateway.selectExecutor({ taskType: 'h5_chat_code_task' }),
'cursor',
);
assert.equal(gateway.selectExecutor({ taskType: 'small_patch' }), 'aider');
});
test('tool gateway honors explicit cursor executor in run metadata', () => {
const gateway = createToolGateway({
env: { MEMIND_CURSOR_EXECUTOR_ENABLED: '1' },
});
assert.equal(gateway.selectExecutor({
taskType: 'page_data_dev_complex',
userMessage: {
metadata: {
memindRun: {
executor: 'cursor',
},
},
},
}), 'cursor');
});
test('tool gateway honors requiredExecutor when executor is absent', () => {
const gateway = createToolGateway({
env: { MEMIND_CURSOR_EXECUTOR_ENABLED: '1' },
});
assert.equal(gateway.selectExecutor({
userMessage: {
metadata: {
memindRun: {
requiredExecutor: 'cursor',
channel: 'wechat_mp',
},
},
},
}), 'cursor');
});
test('tool gateway selects openhands for configured task types', () => {
const gateway = createToolGateway({
env: {
MEMIND_TOOL_GATEWAY_DEFAULT_EXECUTOR: 'aider',
MEMIND_TOOL_GATEWAY_OPENHANDS_TASK_TYPES: 'repo_refactor',
},
});
assert.equal(gateway.selectExecutor({ taskType: 'repo_refactor' }), 'openhands');
assert.equal(gateway.selectExecutor({ taskType: 'small_patch' }), 'aider');
});
test('tool gateway selects openhands for page_data_dev_complex by default', () => {
const gateway = createToolGateway({ env: {} });
assert.equal(gateway.selectExecutor({ taskType: 'page_data_dev_complex' }), 'openhands');
});
test('tool gateway honors an explicitly required Aider executor over task defaults', () => {
const gateway = createToolGateway({ env: {} });
assert.equal(gateway.selectExecutor({
taskType: 'page_data_dev_complex',
userMessage: {
metadata: {
memindRun: {
executor: 'aider',
selectedChatSkill: 'aider-development',
},
},
},
}), 'aider');
});
test('tool gateway resolves and prepares the required Aider receipt without pre-validating it', async () => {
const requestId = 'req-receipt';
const relativePath = `.memind/agent-runs/${requestId}.json`;
const userMessage = {
metadata: {
memindRun: {
validation: {
expectedFile: { path: relativePath, contains: requestId },
},
},
},
};
assert.equal(resolveAiderReceiptPath(userMessage, requestId), relativePath);
const cwd = await fs.mkdtemp(path.join(os.tmpdir(), 'memind-aider-receipt-'));
try {
const target = await prepareAiderReceiptFile(cwd, relativePath);
const pending = JSON.parse(await fs.readFile(target, 'utf8'));
assert.deepEqual(pending, { status: 'pending', executor: 'aider' });
assert.equal((await fs.readFile(target, 'utf8')).includes(requestId), false);
} finally {
await fs.rm(cwd, { recursive: true, force: true });
}
});
test('tool gateway hardens Aider against repository commits and includes the receipt', () => {
const plan = hardenAiderLaunchPlan(
{ ok: true, args: ['--model', 'test-model'] },
'/tmp/work/.memind/agent-runs/req.json',
['/tmp/work/public/order.html'],
);
assert.ok(plan.args.includes('--no-git'));
assert.ok(plan.args.includes('--no-auto-commits'));
assert.ok(plan.args.includes('--no-dirty-commits'));
assert.deepEqual(
plan.args.slice(-2),
['--file', '/tmp/work/.memind/agent-runs/req.json'],
);
assert.ok(plan.args.includes('/tmp/work/public/order.html'));
});
test('tool gateway dry run builds executor launch plan without spawning', async () => {
const plans = [];
const gateway = createToolGateway({
env: {
MEMIND_TOOL_GATEWAY_ENABLED: '1',
MEMIND_TOOL_GATEWAY_DRY_RUN: '1',
MEMIND_TOOL_GATEWAY_DEFAULT_EXECUTOR: 'aider',
},
llmProviderService: {
async getExecutorLaunchPlan(executor, options) {
plans.push({ executor, options });
return {
ok: true,
executor,
cwd: options.cwd,
command: '/usr/bin/true',
args: ['--noop'],
};
},
},
});
const result = await gateway.executeJob({
runId: 'run-1',
requestId: 'req-1',
userId: 'user-1',
cwd: '/tmp/work',
taskType: 'small_patch',
userMessage: { content: [{ type: 'text', text: 'fix it' }] },
});
assert.equal(result.dryRun, true);
assert.equal(result.executor, 'aider');
assert.equal(result.command, '/usr/bin/true');
assert.equal(plans.length, 1);
assert.equal(plans[0].options.instruction, 'fix it');
});
test('tool gateway exposes dsh executor when enabled', () => {
const gateway = createToolGateway({
env: {
MEMIND_TOOL_GATEWAY_DSH_ENABLED: '1',
MEMIND_TOOL_GATEWAY_DSH_TASK_TYPES: 'repo_refactor',
},
});
assert.deepEqual(gateway.getStatus().executors, ['dsh', 'aider', 'openhands']);
assert.equal(gateway.selectExecutor({ taskType: 'repo_refactor' }), 'dsh');
assert.equal(gateway.selectExecutor({ taskType: 'small_patch' }), 'aider');
});
test('tool gateway dsh dry run uses llm provider launch plan', async () => {
const plans = [];
const gateway = createToolGateway({
env: {
MEMIND_TOOL_GATEWAY_ENABLED: '1',
MEMIND_TOOL_GATEWAY_DRY_RUN: '1',
MEMIND_TOOL_GATEWAY_DSH_ENABLED: '1',
MEMIND_TOOL_GATEWAY_DSH_TASK_TYPES: 'repo_refactor',
},
llmProviderService: {
async getExecutorLaunchPlan(executor, options) {
plans.push({ executor, options });
return {
ok: true,
executor,
cwd: options.cwd,
command: 'npx',
args: ['-y', '@deepseek-ai/dsh', '--profile', 'headless', options.instruction],
};
},
},
});
const result = await gateway.executeJob({
runId: 'run-dsh',
requestId: 'req-dsh',
userId: 'user-1',
cwd: '/tmp/work',
taskType: 'repo_refactor',
userMessage: { content: [{ type: 'text', text: 'refactor auth module' }] },
});
assert.equal(result.dryRun, true);
assert.equal(result.executor, 'dsh');
assert.equal(plans.length, 1);
assert.equal(plans[0].executor, 'dsh');
});
test('tool gateway cursor dry run does not require llm provider service', async () => {
const gateway = createToolGateway({
env: {
MEMIND_TOOL_GATEWAY_ENABLED: '1',
MEMIND_TOOL_GATEWAY_DRY_RUN: '1',
MEMIND_CURSOR_EXECUTOR_ENABLED: '1',
},
});
const result = await gateway.executeJob({
runId: 'run-cursor',
requestId: 'req-cursor',
userId: 'user-1',
cwd: '/tmp/work',
userMessage: {
content: [{ type: 'text', text: 'build page' }],
metadata: {
memindRun: {
requiredExecutor: 'cursor',
},
},
},
});
assert.equal(result.dryRun, true);
assert.equal(result.executor, 'cursor');
assert.equal(result.executorLabel, 'TKMind 智趣');
assert.match(String(result.command), /agent$/);
});