import assert from 'node:assert/strict'; import test from 'node:test'; import { createToolGateway, extractToolInstruction } 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', openhandsTaskTypes: ['repo_refactor', 'multi_file', 'complex_repo', 'page_data_dev_complex'], }); }); 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 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'); });