This commit is contained in:
yumoqing 2026-02-13 17:40:56 +08:00
parent 56602d54a0
commit dc183da3e2

View File

@ -42,7 +42,7 @@ class LLMHandler:
exception(f'{e}\n{format_exc()}')
return txt
async def run_subprocess(command, cwd, env, timeout=30.0):
async def run_subprocess(command, cwd, env, input_str=None, timeout=30.0):
try:
# 启动子进程
# stdout/stderr 设置为 PIPE 对应原来的 capture_output=True
@ -50,6 +50,7 @@ async def run_subprocess(command, cwd, env, timeout=30.0):
command,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
stdin=asyncio.subprocess.PIPE,
cwd=cwd,
env=env,
# 注意asyncio 默认处理字节流,如果需要文本,后面需手动 decode
@ -58,7 +59,8 @@ async def run_subprocess(command, cwd, env, timeout=30.0):
# 使用 wait_for 实现 timeout 功能
try:
# wait_for 会在超时后抛出 TimeoutError 并自动 cancel 协程
stdout, stderr = await asyncio.wait_for(process.communicate(), timeout=timeout)
input_bytes = input_str.encode() if input_str else None
stdout, stderr = await asyncio.wait_for(process.communicate(input=input_bytes), timeout=timeout)
except asyncio.TimeoutError:
process.kill() # 超时强制杀掉进程
await process.wait() # 确保资源回收
@ -130,9 +132,14 @@ class IndustrialSkillEngine:
(skill["root"] / ".deps_installed").touch()
# --- 3. 增强版安全执行器:带重试逻辑与审计 ---
async def _execute_with_retry(self, command: str, skill_name: str, retry_count=1) -> str:
async def _execute_with_retry(self, cmdjson: dict, skill_name: str, retry_count=1) -> str:
await self._ensure_dependencies(skill_name)
command = cmdjson['cmd']
params = cmdjson.get('params')
params_str=None
if params:
params_str = json.dumps(params, ensure_ascii=False)
# 安全预检:禁止敏感命令
forbidden = ["rm ", "> /dev/", "chmod", "sudo"]
if any(f in command for f in forbidden):
@ -143,8 +150,11 @@ class IndustrialSkillEngine:
try:
env = os.environ.copy()
env["SKILL_CONTEXT"] = skill_name
res = await run_subprocess(command, cwd=self.registry[skill_name]["root"], env=env, timeout=30)
intput_str = json.dumps(params, ensure_ascii=False)
res = await run_subprocess(command, cwd=self.registry[skill_name]["root"],
env=env,
input_str=params_str,
timeout=30)
if res.return_code != 0:
# 工业级特性:自动将错误回传给 LLM 进行自愈 (Self-healing)
@ -238,7 +248,7 @@ class IndustrialSkillEngine:
context = await self._get_expanded_context(skill_name, user_prompt, context=context)
# 决策:是直接回答还是执行脚本
decision = await self.llm(f"上下文: {context}\n问题: {user_prompt}\n决定动作EXEC: <command> 或 ANSWER: <text> 或 REPLY: <question>")
decision = await self.llm(f"上下文: {context}\n问题: {user_prompt}\n决定动作EXEC: {"cmd": found_cmd, "params": found_parameters_dict} 或 ANSWER: <text> 或 REPLY: <question>")
output = {
"status": "PROCESSING",
"hint": f"决策完成:{decision=}"
@ -262,7 +272,8 @@ class IndustrialSkillEngine:
return
if "EXEC:" in decision:
cmd = decision.split("EXEC:")[1].strip()
output = await self._execute_with_retry(cmd, skill_name)
jd = json.loads(cmd)
output = await self._execute_with_retry(jd, skill_name)
if isinstance(output, str):
output = {
"status": "SUCCEEDED",