update shell_env

This commit is contained in:
朱潮 2026-03-17 10:09:48 +08:00
parent 8c0e0cf187
commit a05da928f0
2 changed files with 82 additions and 2 deletions

View File

@ -10,6 +10,7 @@ import secrets
import os
import shutil
from datetime import datetime, timedelta
from pathlib import Path
from typing import Optional, List
from fastapi import APIRouter, HTTPException, Header
from pydantic import BaseModel
@ -1803,6 +1804,23 @@ async def get_bot_settings(bot_uuid: str, authorization: Optional[str] = Header(
elif not dataset_ids:
dataset_ids = None
# 扫描 skills 需要的环境变量并合并到 shell_env
shell_env = settings.get('shell_env') or {}
skills_list = settings.get('skills')
if skills_list:
from utils.multi_project_manager import scan_skill_env_keys
# skills 可能是逗号分隔的字符串,需要拆分成列表
if isinstance(skills_list, str):
skills_names = [s.strip() for s in skills_list.split(',') if s.strip()]
else:
skills_names = skills_list
required_keys = scan_skill_env_keys(bot_uuid, skills_names, Path("projects"))
for key in required_keys:
if key not in shell_env:
shell_env[key] = ''
# 清理不在 skill 所需变量中且值为空的环境变量
shell_env = {k: v for k, v in shell_env.items() if v or k in required_keys}
return BotSettingsResponse(
bot_id=str(bot_id),
name=bot_name,
@ -1818,8 +1836,8 @@ async def get_bot_settings(bot_uuid: str, authorization: Optional[str] = Header(
enable_memori=settings.get('enable_memori', False),
enable_thinking=settings.get('enable_thinking', False),
tool_response=settings.get('tool_response', False),
skills=settings.get('skills'),
shell_env=settings.get('shell_env'),
skills=skills_list,
shell_env=shell_env,
is_published=is_published if is_published else False,
is_owner=is_owner,
copied_from=str(copied_from) if copied_from else None,

View File

@ -4,6 +4,7 @@
"""
import os
import re
import shutil
import json
import logging
@ -426,3 +427,64 @@ def _extract_skills_to_robot(bot_id: str, skills: List[str], project_path: Path)
logger.info(f" Copied: {source_dir} -> {target_dir}")
except Exception as e:
logger.error(f" Failed to copy {source_dir}: {e}")
_COMMON_ENV_KEYS = frozenset({
'TMPDIR', 'PATH', 'HOME', 'USER', 'SHELL', 'LANG', 'TERM',
'PWD', 'OLDPWD', 'NODE_ENV',
})
_ENV_PATTERNS = [
re.compile(r'process\.env\.(\w+)'),
re.compile(r'os\.getenv\([\'"](\w+)'),
re.compile(r'os\.environ\.get\([\'"](\w+)'),
re.compile(r'os\.environ\[[\'"](\w+)'),
]
_SCAN_EXTENSIONS = {'.js', '.py', '.ts', '.sh', '.md', '.jsx', '.tsx', '.mjs', '.cjs'}
def scan_skill_env_keys(bot_id: str, skills: List[str], project_path: Path) -> set:
"""
扫描 skills 目录下所有文件提取引用的环境变量 KEY
Args:
bot_id: 机器人 ID
skills: 技能名称列表
project_path: 项目路径 Path("projects")
Returns:
set: 环境变量 KEY 集合排除通用变量
"""
skills_source_dirs = [
project_path / "uploads" / bot_id / "skills",
Path("skills"),
]
env_keys = set()
for skill in skills:
source_dir = None
for base_dir in skills_source_dirs:
candidate = base_dir / skill
if candidate.exists():
source_dir = candidate
break
if source_dir is None or not source_dir.exists():
continue
for file_path in source_dir.rglob('*'):
if not file_path.is_file():
continue
if file_path.suffix.lower() not in _SCAN_EXTENSIONS:
continue
try:
content = file_path.read_text(encoding='utf-8', errors='ignore')
except Exception:
continue
for pattern in _ENV_PATTERNS:
env_keys.update(pattern.findall(content))
env_keys -= _COMMON_ENV_KEYS
return env_keys