From dc183da3e2db11c3498fba398dce4fbd0cee615c Mon Sep 17 00:00:00 2001 From: yumoqing Date: Fri, 13 Feb 2026 17:40:56 +0800 Subject: [PATCH] bugfix --- skillagent/skillengine.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/skillagent/skillengine.py b/skillagent/skillengine.py index 8044a24..38046d5 100644 --- a/skillagent/skillengine.py +++ b/skillagent/skillengine.py @@ -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: 或 ANSWER: 或 REPLY: ") + decision = await self.llm(f"上下文: {context}\n问题: {user_prompt}\n决定动作:EXEC: {"cmd": found_cmd, "params": found_parameters_dict} 或 ANSWER: 或 REPLY: ") 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",