bugfix
This commit is contained in:
parent
56602d54a0
commit
dc183da3e2
@ -42,7 +42,7 @@ class LLMHandler:
|
|||||||
exception(f'{e}\n{format_exc()}')
|
exception(f'{e}\n{format_exc()}')
|
||||||
return txt
|
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:
|
try:
|
||||||
# 启动子进程
|
# 启动子进程
|
||||||
# stdout/stderr 设置为 PIPE 对应原来的 capture_output=True
|
# stdout/stderr 设置为 PIPE 对应原来的 capture_output=True
|
||||||
@ -50,6 +50,7 @@ async def run_subprocess(command, cwd, env, timeout=30.0):
|
|||||||
command,
|
command,
|
||||||
stdout=asyncio.subprocess.PIPE,
|
stdout=asyncio.subprocess.PIPE,
|
||||||
stderr=asyncio.subprocess.PIPE,
|
stderr=asyncio.subprocess.PIPE,
|
||||||
|
stdin=asyncio.subprocess.PIPE,
|
||||||
cwd=cwd,
|
cwd=cwd,
|
||||||
env=env,
|
env=env,
|
||||||
# 注意:asyncio 默认处理字节流,如果需要文本,后面需手动 decode
|
# 注意:asyncio 默认处理字节流,如果需要文本,后面需手动 decode
|
||||||
@ -58,7 +59,8 @@ async def run_subprocess(command, cwd, env, timeout=30.0):
|
|||||||
# 使用 wait_for 实现 timeout 功能
|
# 使用 wait_for 实现 timeout 功能
|
||||||
try:
|
try:
|
||||||
# wait_for 会在超时后抛出 TimeoutError 并自动 cancel 协程
|
# 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:
|
except asyncio.TimeoutError:
|
||||||
process.kill() # 超时强制杀掉进程
|
process.kill() # 超时强制杀掉进程
|
||||||
await process.wait() # 确保资源回收
|
await process.wait() # 确保资源回收
|
||||||
@ -130,9 +132,14 @@ class IndustrialSkillEngine:
|
|||||||
(skill["root"] / ".deps_installed").touch()
|
(skill["root"] / ".deps_installed").touch()
|
||||||
|
|
||||||
# --- 3. 增强版安全执行器:带重试逻辑与审计 ---
|
# --- 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)
|
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"]
|
forbidden = ["rm ", "> /dev/", "chmod", "sudo"]
|
||||||
if any(f in command for f in forbidden):
|
if any(f in command for f in forbidden):
|
||||||
@ -143,8 +150,11 @@ class IndustrialSkillEngine:
|
|||||||
try:
|
try:
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env["SKILL_CONTEXT"] = skill_name
|
env["SKILL_CONTEXT"] = skill_name
|
||||||
|
intput_str = json.dumps(params, ensure_ascii=False)
|
||||||
res = await run_subprocess(command, cwd=self.registry[skill_name]["root"], env=env, timeout=30)
|
res = await run_subprocess(command, cwd=self.registry[skill_name]["root"],
|
||||||
|
env=env,
|
||||||
|
input_str=params_str,
|
||||||
|
timeout=30)
|
||||||
|
|
||||||
if res.return_code != 0:
|
if res.return_code != 0:
|
||||||
# 工业级特性:自动将错误回传给 LLM 进行自愈 (Self-healing)
|
# 工业级特性:自动将错误回传给 LLM 进行自愈 (Self-healing)
|
||||||
@ -238,7 +248,7 @@ class IndustrialSkillEngine:
|
|||||||
context = await self._get_expanded_context(skill_name, user_prompt, context=context)
|
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 = {
|
output = {
|
||||||
"status": "PROCESSING",
|
"status": "PROCESSING",
|
||||||
"hint": f"决策完成:{decision=}"
|
"hint": f"决策完成:{decision=}"
|
||||||
@ -262,7 +272,8 @@ class IndustrialSkillEngine:
|
|||||||
return
|
return
|
||||||
if "EXEC:" in decision:
|
if "EXEC:" in decision:
|
||||||
cmd = decision.split("EXEC:")[1].strip()
|
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):
|
if isinstance(output, str):
|
||||||
output = {
|
output = {
|
||||||
"status": "SUCCEEDED",
|
"status": "SUCCEEDED",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user