mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 15:38:19 +08:00
fix: cache available shell command discovery
This commit is contained in:
@@ -142,6 +142,7 @@ class PromptManager:
|
|||||||
self.prompts_cache: Dict[str, str] = {}
|
self.prompts_cache: Dict[str, str] = {}
|
||||||
self._system_tasks_cache: Optional[SystemTasksDefinition] = None
|
self._system_tasks_cache: Optional[SystemTasksDefinition] = None
|
||||||
self._system_tasks_signature: Optional[tuple[int, int]] = None
|
self._system_tasks_signature: Optional[tuple[int, int]] = None
|
||||||
|
self._available_shell_commands_cache: Optional[list[tuple[str, str]]] = None
|
||||||
|
|
||||||
def load_prompt(self, prompt_name: str) -> str:
|
def load_prompt(self, prompt_name: str) -> str:
|
||||||
"""
|
"""
|
||||||
@@ -329,8 +330,7 @@ class PromptManager:
|
|||||||
sections.append(self._format_numbered_rules("IMPORTANT", rules))
|
sections.append(self._format_numbered_rules("IMPORTANT", rules))
|
||||||
return "\n\n".join(section for section in sections if section).strip()
|
return "\n\n".join(section for section in sections if section).strip()
|
||||||
|
|
||||||
@staticmethod
|
def _get_moviepilot_info(self) -> str:
|
||||||
def _get_moviepilot_info() -> str:
|
|
||||||
"""
|
"""
|
||||||
获取MoviePilot系统信息,用于注入到系统提示词中
|
获取MoviePilot系统信息,用于注入到系统提示词中
|
||||||
"""
|
"""
|
||||||
@@ -382,7 +382,7 @@ class PromptManager:
|
|||||||
f"- 系统安装目录: {settings.ROOT_PATH}",
|
f"- 系统安装目录: {settings.ROOT_PATH}",
|
||||||
]
|
]
|
||||||
|
|
||||||
available_commands = PromptManager._get_available_shell_commands()
|
available_commands = self._get_available_shell_commands()
|
||||||
if available_commands:
|
if available_commands:
|
||||||
info_lines.append("- 可用系统命令(可通过 `execute_command` 调用):")
|
info_lines.append("- 可用系统命令(可通过 `execute_command` 调用):")
|
||||||
info_lines.extend(
|
info_lines.extend(
|
||||||
@@ -391,21 +391,29 @@ class PromptManager:
|
|||||||
|
|
||||||
return "\n".join(info_lines)
|
return "\n".join(info_lines)
|
||||||
|
|
||||||
@staticmethod
|
def _get_available_shell_commands(self) -> list[tuple[str, str]]:
|
||||||
def _get_available_shell_commands() -> list[tuple[str, str]]:
|
|
||||||
"""
|
"""
|
||||||
探测 PATH 中已经安装的常用命令。
|
探测 PATH 中已经安装的常用命令。
|
||||||
|
|
||||||
这里只使用 shutil.which 做无副作用查找,不实际执行命令;执行权限、
|
这里只使用 shutil.which 做无副作用查找,不实际执行命令;执行权限、
|
||||||
高风险操作确认和输出限制仍由 execute_command 工具负责。
|
高风险操作确认和输出限制仍由 execute_command 工具负责。探测结果
|
||||||
|
在进程内缓存,避免每次组装提示词都重复扫描 PATH。
|
||||||
"""
|
"""
|
||||||
|
if self._available_shell_commands_cache is not None:
|
||||||
|
return self._available_shell_commands_cache
|
||||||
|
|
||||||
available_commands: list[tuple[str, str]] = []
|
available_commands: list[tuple[str, str]] = []
|
||||||
for command in COMMON_SHELL_COMMANDS:
|
for command in COMMON_SHELL_COMMANDS:
|
||||||
command_path = shutil.which(command)
|
command_path = shutil.which(command)
|
||||||
if command_path:
|
if command_path:
|
||||||
available_commands.append((command, command_path))
|
available_commands.append((command, command_path))
|
||||||
|
self._available_shell_commands_cache = available_commands
|
||||||
return available_commands
|
return available_commands
|
||||||
|
|
||||||
|
def clear_available_shell_commands_cache(self) -> None:
|
||||||
|
"""清理可用系统命令缓存,供测试或运行时手动刷新使用。"""
|
||||||
|
self._available_shell_commands_cache = None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _generate_formatting_instructions(caps: ChannelCapabilities) -> str:
|
def _generate_formatting_instructions(caps: ChannelCapabilities) -> str:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from unittest.mock import patch
|
|||||||
|
|
||||||
from app.agent.middleware.memory import MEMORY_ONBOARDING_PROMPT
|
from app.agent.middleware.memory import MEMORY_ONBOARDING_PROMPT
|
||||||
from app.agent.middleware.runtime_config import RuntimeConfigMiddleware
|
from app.agent.middleware.runtime_config import RuntimeConfigMiddleware
|
||||||
from app.agent.prompt import PromptConfigError, prompt_manager
|
from app.agent.prompt import COMMON_SHELL_COMMANDS, PromptConfigError, prompt_manager
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
|
||||||
|
|
||||||
@@ -16,6 +16,14 @@ class _FakeRequest:
|
|||||||
|
|
||||||
|
|
||||||
class TestAgentPromptStyle(unittest.TestCase):
|
class TestAgentPromptStyle(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
"""每个用例前清理系统命令缓存,避免本机 PATH 或测试顺序影响断言。"""
|
||||||
|
prompt_manager.clear_available_shell_commands_cache()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""每个用例后清理系统命令缓存,避免 mock 探测结果泄漏到后续用例。"""
|
||||||
|
prompt_manager.clear_available_shell_commands_cache()
|
||||||
|
|
||||||
def test_base_prompt_mentions_persona_management_tools(self):
|
def test_base_prompt_mentions_persona_management_tools(self):
|
||||||
prompt = prompt_manager.get_agent_prompt()
|
prompt = prompt_manager.get_agent_prompt()
|
||||||
|
|
||||||
@@ -62,6 +70,20 @@ class TestAgentPromptStyle(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertNotIn("可用系统命令", prompt)
|
self.assertNotIn("可用系统命令", prompt)
|
||||||
|
|
||||||
|
def test_available_shell_commands_are_cached_after_first_scan(self):
|
||||||
|
"""常用命令探测应只在首次加载时扫描 PATH,后续提示词复用缓存。"""
|
||||||
|
command_paths = {"ssh": "/usr/bin/ssh"}
|
||||||
|
with patch(
|
||||||
|
"app.agent.prompt.shutil.which",
|
||||||
|
side_effect=lambda command: command_paths.get(command),
|
||||||
|
) as which_mock:
|
||||||
|
first_prompt = prompt_manager.get_agent_prompt()
|
||||||
|
second_prompt = prompt_manager.get_agent_prompt()
|
||||||
|
|
||||||
|
self.assertIn(" - ssh: /usr/bin/ssh", first_prompt)
|
||||||
|
self.assertIn(" - ssh: /usr/bin/ssh", second_prompt)
|
||||||
|
self.assertEqual(which_mock.call_count, len(COMMON_SHELL_COMMANDS))
|
||||||
|
|
||||||
def test_runtime_config_middleware_injects_persona_only(self):
|
def test_runtime_config_middleware_injects_persona_only(self):
|
||||||
middleware = RuntimeConfigMiddleware()
|
middleware = RuntimeConfigMiddleware()
|
||||||
updated_request = middleware.modify_request(_FakeRequest())
|
updated_request = middleware.modify_request(_FakeRequest())
|
||||||
|
|||||||
Reference in New Issue
Block a user