// DSH ACP 语言策略验证:用【英文】提问,检查回复是否仍为中文(全局指令生效则应为中文) import { spawn } from 'node:child_process'; const child = spawn('dsh', ['--profile', 'acp'], { stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, PATH: `/home/yangxuan/.nvm/versions/node/v26.8.2/bin:${process.env.PATH}` }, cwd: '/home/yangxuan', }); let buf = ''; const pending = new Map(); let nextId = 0; const notifications = []; child.stdout.on('data', (d) => { buf += d.toString(); let i; while ((i = buf.indexOf('\n')) >= 0) { const line = buf.slice(0, i).trim(); buf = buf.slice(i + 1); if (!line) continue; let msg; try { msg = JSON.parse(line); } catch { console.log('[非 JSON 的 stdout 输出]', line.slice(0, 160)); continue; } handle(msg); } }); child.stderr.on('data', (d) => process.stderr.write('[stderr] ' + d.toString())); function send(msg) { child.stdin.write(JSON.stringify(msg) + '\n'); } function call(method, params, timeoutMs = 180000) { const id = ++nextId; return new Promise((resolve, reject) => { const t = setTimeout(() => { pending.delete(id); reject(new Error(`timeout: ${method}`)); }, timeoutMs); pending.set(id, { resolve: (v) => { clearTimeout(t); resolve(v); }, reject: (e) => { clearTimeout(t); reject(e); } }); send({ jsonrpc: '2.0', id, method, params }); }); } function handle(msg) { if (msg.id !== undefined && msg.method === 'session/request_permission') { send({ jsonrpc: '2.0', id: msg.id, result: { outcome: { outcome: 'selected', optionId: msg.params?.options?.[0]?.optionId } } }); return; } if (msg.id !== undefined && (msg.result !== undefined || msg.error !== undefined)) { const p = pending.get(msg.id); if (!p) return; pending.delete(msg.id); msg.error ? p.reject(new Error(JSON.stringify(msg.error))) : p.resolve(msg.result); return; } if (msg.method) notifications.push(msg); } try { await call('initialize', { protocolVersion: 1, clientCapabilities: { fs: { readTextFile: false, writeTextFile: false } }, clientInfo: { name: 'dsh-lang-check', version: '0.0.1' } }); const sess = await call('session/new', { cwd: '/home/yangxuan', mcpServers: [] }); const sid = sess.sessionId; const prompts = [ 'Answer in ONE short sentence, English only: what is 2+2?', 'Reply with a single short sentence: name one benefit of unit tests.', ]; for (const text of prompts) { notifications.length = 0; const before = notifications.length; const res = await call('session/prompt', { sessionId: sid, prompt: [{ type: 'text', text }] }); const reply = notifications .map((n) => n.params?.update) .filter((u) => u?.sessionUpdate === 'agent_message_chunk') .map((u) => u?.content?.text ?? '') .join(''); const cjk = (reply.match(/[\u4e00-\u9fff]/g) || []).length; const latin = (reply.match(/[A-Za-z]/g) || []).length; console.log('--- 提问(英文):', text); console.log(' 回复:', reply.trim().slice(0, 200)); console.log(' stopReason:', res.stopReason, '| 中文字符数:', cjk, '| 拉丁字母数:', latin, '| 判定:', cjk > 0 && cjk >= latin / 2 ? '中文(指令生效)' : '非中文(指令未生效?)'); } await call('session/close', { sessionId: sid }, 60000).catch(() => {}); } catch (err) { console.log('!! 失败:', err.message); } finally { child.kill('SIGTERM'); setTimeout(() => process.exit(0), 1200); }