Skip to content

Commit 621061b

Browse files
committed
feat: 增加一个沙盒运行代码的工具函数
1 parent 05f5b9c commit 621061b

File tree

1 file changed

+95
-0
lines changed

1 file changed

+95
-0
lines changed

src/apiTools.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,7 +1314,102 @@ interface IErrorInfo
13141314
// 注册工具
13151315
registerTool(diagnosticTop5Errors);
13161316

1317+
// 12. 沙盒执行 Lua/Python 代码
1318+
export const sandboxRun: Tool = {
1319+
name: 'sandbox_run',
1320+
description: `在沙盒环境中执行 Lua 或 Python 代码,并返回标准输出、标准错误。禁止访问文件系统。`,
1321+
parameters: {
1322+
type: 'object',
1323+
properties: {
1324+
language: { type: 'string', description: '执行语言(lua 或 python)' },
1325+
code: { type: 'string', description: '要执行的代码内容。' },
1326+
input: { type: 'string', description: '可选的标准输入内容(stdin)。' }
1327+
},
1328+
required: ['language', 'code'],
1329+
},
1330+
function: async (args: { language: 'lua' | 'python'; code: string; input?: string }) => {
1331+
const strLanguage: string = args.language;
1332+
const strCode: string = args.code;
1333+
const strInput: string = args.input ?? '';
1334+
1335+
try
1336+
{
1337+
// 简单敏感词检测
1338+
const arrForbidden: string[] = ['os.', 'io.', 'open(', 'require(', 'import os', 'import shutil']
1339+
for (const strBad of arrForbidden)
1340+
{
1341+
if (strCode.includes(strBad))
1342+
{
1343+
return `安全警告:代码中包含禁止的调用 (${strBad})`
1344+
}
1345+
}
1346+
1347+
let strCommand: string = '';
1348+
let arrArgs: string[] = [];
1349+
1350+
if (strLanguage === 'lua')
1351+
{
1352+
strCommand = 'lua';
1353+
arrArgs = ['-e', strCode];
1354+
}
1355+
else if (strLanguage === 'python')
1356+
{
1357+
strCommand = 'python';
1358+
arrArgs = ['-c', strCode];
1359+
}
1360+
else
1361+
{
1362+
return `不支持的语言类型: ${strLanguage}`
1363+
}
1364+
1365+
return await new Promise<string>((resolve, reject) =>
1366+
{
1367+
const objChild = childProcess.spawn(strCommand, arrArgs, { stdio: ['pipe', 'pipe', 'pipe'] });
1368+
1369+
let strStdout: string = '';
1370+
let strStderr: string = '';
1371+
1372+
objChild.stdout.on('data', (data) => {
1373+
strStdout += data.toString();
1374+
});
1375+
1376+
objChild.stderr.on('data', (data) => {
1377+
strStderr += data.toString();
1378+
});
1379+
1380+
objChild.on('error', (error) => {
1381+
reject(`执行出错: ${error.message}`);
1382+
});
1383+
1384+
objChild.on('close', (code) => {
1385+
resolve(JSON.stringify({
1386+
exitCode: code,
1387+
stdout: strStdout.trim(),
1388+
stderr: strStderr.trim(),
1389+
}, null, 4));
1390+
});
1391+
1392+
// 写入标准输入
1393+
if (strInput.length > 0)
1394+
{
1395+
objChild.stdin.write(strInput)
1396+
}
1397+
objChild.stdin.end();
1398+
1399+
// 超时保护(3秒)
1400+
setTimeout(() => {
1401+
objChild.kill('SIGKILL');
1402+
}, 3000);
1403+
});
1404+
}
1405+
catch (error: any)
1406+
{
1407+
return `沙盒执行失败: ${error.message}`;
1408+
}
1409+
},
1410+
}
13171411

1412+
registerTool(sandboxRun)
13181413

13191414

13201415

0 commit comments

Comments
 (0)