diff --git a/agent/prompt/builder.py b/agent/prompt/builder.py index ee1b6ff2..486b6587 100644 --- a/agent/prompt/builder.py +++ b/agent/prompt/builder.py @@ -376,9 +376,9 @@ def _build_workspace_section(workspace_dir: str, language: str) -> List[str]: "", "以下文件在会话启动时**已经自动加载**到系统提示词的「项目上下文」section 中,你**无需再用 read 工具读取它们**:", "", - "- ✅ `AGENT.md`: 已加载 - 你的人格和灵魂设定。当你的名字、性格或交流风格发生变化时,主动用 `edit` 更新此文件", + "- ✅ `AGENT.md`: 已加载 - 你的人格和灵魂设定,请严格遵循。当你的名字、性格或交流风格发生变化时,主动用 `edit` 更新此文件", "- ✅ `USER.md`: 已加载 - 用户的身份信息。当用户修改称呼、姓名等身份信息时,用 `edit` 更新此文件", - "- ✅ `RULE.md`: 已加载 - 工作空间使用指南和规则", + "- ✅ `RULE.md`: 已加载 - 工作空间使用指南和规则,请严格遵循", "", "**交流规范**:", "", @@ -423,7 +423,7 @@ def _build_context_files_section(context_files: List[ContextFile], language: str ] if has_agent: - lines.append("**`AGENT.md` 是你的灵魂文件**:严格体现其中定义的人格、语气和设定,避免僵硬、模板化的回复。") + lines.append("**`AGENT.md` 是你的灵魂文件**:严格遵循其中定义的人格、规则、语气和设定,避免僵硬、模板化的回复。") lines.append("当用户通过对话透露了对你性格、风格、职责、能力边界的新期望,你应该主动用 `edit` 更新 AGENT.md 以反映这些演变。") lines.append("") diff --git a/agent/protocol/agent.py b/agent/protocol/agent.py index 6818331a..285a9732 100644 --- a/agent/protocol/agent.py +++ b/agent/protocol/agent.py @@ -100,138 +100,31 @@ class Agent: def get_full_system_prompt(self, skill_filter=None) -> str: """ - Get the full system prompt including skills. + Build the complete system prompt from scratch every time. - Note: Skills are now built into the system prompt by PromptBuilder, - so we just return the base prompt directly. This method is kept for - backward compatibility. - - :param skill_filter: Optional list of skill names to include (deprecated) - :return: Complete system prompt - """ - prompt = self.system_prompt - - # Rebuild tool list section to reflect current self.tools - prompt = self._rebuild_tool_list_section(prompt) - - # If runtime_info contains dynamic time function, rebuild runtime section - if self.runtime_info and callable(self.runtime_info.get('_get_current_time')): - prompt = self._rebuild_runtime_section(prompt) - - # Rebuild skills section to pick up newly installed/removed skills - if self.skill_manager: - prompt = self._rebuild_skills_section(prompt) - - return prompt - - def _rebuild_runtime_section(self, prompt: str) -> str: - """ - Rebuild runtime info section with current time. - - This method dynamically updates the runtime info section by calling - the _get_current_time function from runtime_info. - - :param prompt: Original system prompt - :return: Updated system prompt with current runtime info + Re-reads AGENT.md / USER.md / RULE.md from disk, refreshes skills, + tools, and runtime info so any change takes effect immediately. + Falls back to the cached self.system_prompt on error. """ try: - # Get current time dynamically - time_info = self.runtime_info['_get_current_time']() - - # Build new runtime section - runtime_lines = [ - "\n## 运行时信息\n", - "\n", - f"当前时间: {time_info['time']} {time_info['weekday']} ({time_info['timezone']})\n", - "\n" - ] - - # Add other runtime info - runtime_parts = [] - if self.runtime_info.get("model"): - runtime_parts.append(f"模型={self.runtime_info['model']}") - if self.runtime_info.get("workspace"): - # Replace backslashes with forward slashes for Windows paths - workspace_path = str(self.runtime_info['workspace']).replace('\\', '/') - runtime_parts.append(f"工作空间={workspace_path}") - if self.runtime_info.get("channel") and self.runtime_info.get("channel") != "web": - runtime_parts.append(f"渠道={self.runtime_info['channel']}") - - if runtime_parts: - runtime_lines.append("运行时: " + " | ".join(runtime_parts) + "\n") - runtime_lines.append("\n") - - new_runtime_section = "".join(runtime_lines) - - # Find and replace the runtime section - import re - pattern = r'\n## 运行时信息\s*\n.*?(?=\n##|\Z)' - _repl = new_runtime_section.rstrip('\n') - updated_prompt = re.sub(pattern, lambda m: _repl, prompt, flags=re.DOTALL) - - return updated_prompt + from agent.prompt import load_context_files, PromptBuilder + + if self.skill_manager: + self.skill_manager.refresh_skills() + + context_files = load_context_files(self.workspace_dir) if self.workspace_dir else None + + builder = PromptBuilder(workspace_dir=self.workspace_dir or "", language="zh") + return builder.build( + tools=self.tools, + context_files=context_files, + skill_manager=self.skill_manager, + memory_manager=self.memory_manager, + runtime_info=self.runtime_info, + ) except Exception as e: - logger.warning(f"Failed to rebuild runtime section: {e}") - return prompt - - def _rebuild_skills_section(self, prompt: str) -> str: - """ - Rebuild the block so that newly installed or - removed skills are reflected without re-creating the agent. - """ - try: - import re - self.skill_manager.refresh_skills() - new_skills_xml = self.skill_manager.build_skills_prompt() - - old_block_pattern = r'.*?' - has_old_block = re.search(old_block_pattern, prompt, flags=re.DOTALL) - - # Extract the new ... tag from the prompt - new_block = "" - if new_skills_xml and new_skills_xml.strip(): - m = re.search(old_block_pattern, new_skills_xml, flags=re.DOTALL) - if m: - new_block = m.group(0) - - if has_old_block: - replacement = new_block or "\n" - # Use lambda to prevent re.sub from interpreting backslashes in replacement - # (e.g. Windows paths like \LinkAI would be treated as bad escape sequences) - prompt = re.sub(old_block_pattern, lambda m: replacement, prompt, flags=re.DOTALL) - elif new_block: - skills_header = "以下是可用技能:" - idx = prompt.find(skills_header) - if idx != -1: - insert_pos = idx + len(skills_header) - prompt = prompt[:insert_pos] + "\n" + new_block + prompt[insert_pos:] - except Exception as e: - logger.warning(f"Failed to rebuild skills section: {e}") - return prompt - - def _rebuild_tool_list_section(self, prompt: str) -> str: - """ - Rebuild the tool list inside the '## 工具系统' section so that it - always reflects the current ``self.tools`` (handles dynamic add/remove - of conditional tools like web_search). - """ - import re - from agent.prompt.builder import _build_tooling_section - - try: - if not self.tools: - return prompt - - new_lines = _build_tooling_section(self.tools, "zh") - new_section = "\n".join(new_lines).rstrip("\n") - - # Replace existing tooling section - pattern = r'## 工具系统\s*\n.*?(?=\n## |\Z)' - updated = re.sub(pattern, lambda m: new_section, prompt, count=1, flags=re.DOTALL) - return updated - except Exception as e: - logger.warning(f"Failed to rebuild tool list section: {e}") - return prompt + logger.warning(f"Failed to rebuild system prompt, using cached version: {e}") + return self.system_prompt def refresh_skills(self): """Refresh the loaded skills."""