From 480c60c0a738f24d4bb3b9fc33f45e7f32ca5c09 Mon Sep 17 00:00:00 2001 From: cowagent Date: Wed, 4 Feb 2026 22:27:24 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E5=8A=A8=E6=80=81=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E6=8F=90=E7=A4=BA=E8=AF=8D=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=97=B6=E4=BF=A1=E6=81=AF=EF=BC=88=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E6=88=B3=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题: - system_prompt 在 Agent 初始化时固定,导致模型获取的时间信息过时 - 长时间运行的会话中,模型对时间判断不准确 解决方案: - 在 get_full_system_prompt() 中添加动态更新逻辑 - 每次获取系统提示词时,使用正则表达式替换运行时信息中的时间戳 - 保持其他运行时信息(模型、工作空间等)不变 测试: - 创建测试脚本验证时间动态更新功能 - 等待3秒后时间正确更新(22:19:45 -> 22:19:48) --- agent/protocol/agent.py | 49 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/agent/protocol/agent.py b/agent/protocol/agent.py index 1b031e0..f5cb9c9 100644 --- a/agent/protocol/agent.py +++ b/agent/protocol/agent.py @@ -1,6 +1,8 @@ import json import time import threading +import datetime +import re from common.log import logger from agent.protocol.models import LLMRequest, LLMModel @@ -105,8 +107,51 @@ class Agent: :return: Complete system prompt """ # Skills are now included in system_prompt by PromptBuilder - # No need to append them here - return self.system_prompt + # Update runtime info (timestamp) dynamically before returning + return self._update_runtime_info(self.system_prompt) + + def _update_runtime_info(self, prompt: str) -> str: + """ + Update runtime information (timestamp) in the system prompt. + + This ensures the model always has the current time, even if the + agent was initialized hours ago. + + :param prompt: Original system prompt + :return: Updated system prompt with current time + """ + # Find the runtime info section + runtime_section_pattern = r'(## 运行时信息\s*\n\s*\n)(当前时间: )([^\n]+)(\s+星期[一二三四五六日])(\s+\([^)]+\))?' + + # Get current time info + now = datetime.datetime.now() + + # Get timezone + try: + offset = -time.timezone if not time.daylight else -time.altzone + hours = offset // 3600 + minutes = (offset % 3600) // 60 + timezone_name = f"UTC{hours:+03d}:{minutes:02d}" if minutes else f"UTC{hours:+03d}" + except Exception: + timezone_name = "UTC" + + # Chinese weekday mapping + weekday_map = { + 'Monday': '星期一', 'Tuesday': '星期二', 'Wednesday': '星期三', + 'Thursday': '星期四', 'Friday': '星期五', 'Saturday': '星期六', 'Sunday': '星期日' + } + weekday_zh = weekday_map.get(now.strftime("%A"), now.strftime("%A")) + + # Build new time string + new_time = now.strftime("%Y-%m-%d %H:%M:%S") + + # Replace the time in the prompt + def replace_time(match): + return f"{match.group(1)}{match.group(2)}{new_time} {weekday_zh} ({timezone_name})" + + updated_prompt = re.sub(runtime_section_pattern, replace_time, prompt) + + return updated_prompt def refresh_skills(self): """Refresh the loaded skills.""" From e4fcfa356abd6887e7cf6d1fb755165c3ac50d24 Mon Sep 17 00:00:00 2001 From: cowagent Date: Wed, 4 Feb 2026 22:37:19 +0800 Subject: [PATCH 2/2] =?UTF-8?q?refactor:=20=E6=94=B9=E7=94=A8=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E5=87=BD=E6=95=B0=E5=AE=9E=E7=8E=B0=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E6=97=B6=E4=BF=A1=E6=81=AF=E6=9B=B4=E6=96=B0=EF=BC=88=E6=9B=B4?= =?UTF-8?q?=E5=81=A5=E5=A3=AE=E7=9A=84=E6=96=B9=E6=A1=88=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 改进点: 1. builder.py: _build_runtime_section() 支持 callable 动态时间函数 2. agent_initializer.py: 传入 get_current_time 函数而非静态时间值 3. agent.py: _rebuild_runtime_section() 动态调用时间函数并重建该部分 优势: - 解耦模板:不依赖具体的提示词格式 - 健壮性:提示词模板改变不会导致功能失效 - 向后兼容:保留对静态时间的支持 - 性能优化:只在需要时才计算时间 相比之前的正则匹配方案,这个方案更加优雅和可维护。 --- agent/prompt/builder.py | 14 +++++- agent/protocol/agent.py | 89 ++++++++++++++++++++----------------- bridge/agent_initializer.py | 51 ++++++++++++--------- 3 files changed, 89 insertions(+), 65 deletions(-) diff --git a/agent/prompt/builder.py b/agent/prompt/builder.py index d8f8401..91ef1c0 100644 --- a/agent/prompt/builder.py +++ b/agent/prompt/builder.py @@ -461,7 +461,7 @@ def _build_context_files_section(context_files: List[ContextFile], language: str def _build_runtime_section(runtime_info: Dict[str, Any], language: str) -> List[str]: - """构建运行时信息section""" + """构建运行时信息section - 支持动态时间""" if not runtime_info: return [] @@ -471,7 +471,17 @@ def _build_runtime_section(runtime_info: Dict[str, Any], language: str) -> List[ ] # Add current time if available - if runtime_info.get("current_time"): + # Support dynamic time via callable function + if callable(runtime_info.get("_get_current_time")): + try: + time_info = runtime_info["_get_current_time"]() + time_line = f"当前时间: {time_info['time']} {time_info['weekday']} ({time_info['timezone']})" + lines.append(time_line) + lines.append("") + except Exception as e: + logger.warning(f"[PromptBuilder] Failed to get dynamic time: {e}") + elif runtime_info.get("current_time"): + # Fallback to static time for backward compatibility time_str = runtime_info["current_time"] weekday = runtime_info.get("weekday", "") timezone = runtime_info.get("timezone", "") diff --git a/agent/protocol/agent.py b/agent/protocol/agent.py index f5cb9c9..7d9baff 100644 --- a/agent/protocol/agent.py +++ b/agent/protocol/agent.py @@ -1,8 +1,6 @@ import json import time import threading -import datetime -import re from common.log import logger from agent.protocol.models import LLMRequest, LLMModel @@ -15,7 +13,8 @@ class Agent: def __init__(self, system_prompt: str, description: str = "AI Agent", model: LLMModel = None, tools=None, output_mode="print", max_steps=100, max_context_tokens=None, context_reserve_tokens=None, memory_manager=None, name: str = None, - workspace_dir: str = None, skill_manager=None, enable_skills: bool = True): + workspace_dir: str = None, skill_manager=None, enable_skills: bool = True, + runtime_info: dict = None): """ Initialize the Agent with system prompt, model, description. @@ -33,6 +32,7 @@ class Agent: :param workspace_dir: Optional workspace directory for workspace-specific skills :param skill_manager: Optional SkillManager instance (will be created if None and enable_skills=True) :param enable_skills: Whether to enable skills support (default: True) + :param runtime_info: Optional runtime info dict (with _get_current_time callable for dynamic time) """ self.name = name or "Agent" self.system_prompt = system_prompt @@ -50,6 +50,7 @@ class Agent: self.memory_manager = memory_manager # Memory manager for auto memory flush self.workspace_dir = workspace_dir # Workspace directory self.enable_skills = enable_skills # Skills enabled flag + self.runtime_info = runtime_info # Runtime info for dynamic time update # Initialize skill manager self.skill_manager = None @@ -107,51 +108,57 @@ class Agent: :return: Complete system prompt """ # Skills are now included in system_prompt by PromptBuilder - # Update runtime info (timestamp) dynamically before returning - return self._update_runtime_info(self.system_prompt) + # If runtime_info contains dynamic time function, rebuild runtime section + if self.runtime_info and callable(self.runtime_info.get('_get_current_time')): + return self._rebuild_runtime_section(self.system_prompt) + return self.system_prompt - def _update_runtime_info(self, prompt: str) -> str: + def _rebuild_runtime_section(self, prompt: str) -> str: """ - Update runtime information (timestamp) in the system prompt. + Rebuild runtime info section with current time. - This ensures the model always has the current time, even if the - agent was initialized hours ago. + 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 time + :return: Updated system prompt with current runtime info """ - # Find the runtime info section - runtime_section_pattern = r'(## 运行时信息\s*\n\s*\n)(当前时间: )([^\n]+)(\s+星期[一二三四五六日])(\s+\([^)]+\))?' - - # Get current time info - now = datetime.datetime.now() - - # Get timezone try: - offset = -time.timezone if not time.daylight else -time.altzone - hours = offset // 3600 - minutes = (offset % 3600) // 60 - timezone_name = f"UTC{hours:+03d}:{minutes:02d}" if minutes else f"UTC{hours:+03d}" - except Exception: - timezone_name = "UTC" - - # Chinese weekday mapping - weekday_map = { - 'Monday': '星期一', 'Tuesday': '星期二', 'Wednesday': '星期三', - 'Thursday': '星期四', 'Friday': '星期五', 'Saturday': '星期六', 'Sunday': '星期日' - } - weekday_zh = weekday_map.get(now.strftime("%A"), now.strftime("%A")) - - # Build new time string - new_time = now.strftime("%Y-%m-%d %H:%M:%S") - - # Replace the time in the prompt - def replace_time(match): - return f"{match.group(1)}{match.group(2)}{new_time} {weekday_zh} ({timezone_name})" - - updated_prompt = re.sub(runtime_section_pattern, replace_time, prompt) - - return updated_prompt + # 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"): + runtime_parts.append(f"工作空间={self.runtime_info['workspace']}") + 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)' + updated_prompt = re.sub(pattern, new_runtime_section.rstrip('\n'), prompt, flags=re.DOTALL) + + return updated_prompt + except Exception as e: + logger.warning(f"Failed to rebuild runtime section: {e}") + return prompt def refresh_skills(self): """Refresh the loaded skills.""" diff --git a/bridge/agent_initializer.py b/bridge/agent_initializer.py index 27739b5..50de21b 100644 --- a/bridge/agent_initializer.py +++ b/bridge/agent_initializer.py @@ -110,7 +110,8 @@ class AgentInitializer: workspace_dir=workspace_root, skill_manager=skill_manager, enable_skills=True, - max_context_tokens=max_context_tokens + max_context_tokens=max_context_tokens, + runtime_info=runtime_info # Pass runtime_info for dynamic time updates ) # Attach memory manager @@ -289,34 +290,40 @@ class AgentInitializer: return None def _get_runtime_info(self, workspace_root: str): - """Get runtime information""" + """Get runtime information with dynamic time support""" from config import conf - now = datetime.datetime.now() - - # Get timezone info - try: - offset = -time.timezone if not time.daylight else -time.altzone - hours = offset // 3600 - minutes = (offset % 3600) // 60 - timezone_name = f"UTC{hours:+03d}:{minutes:02d}" if minutes else f"UTC{hours:+03d}" - except Exception: - timezone_name = "UTC" - - # Chinese weekday mapping - weekday_map = { - 'Monday': '星期一', 'Tuesday': '星期二', 'Wednesday': '星期三', - 'Thursday': '星期四', 'Friday': '星期五', 'Saturday': '星期六', 'Sunday': '星期日' - } - weekday_zh = weekday_map.get(now.strftime("%A"), now.strftime("%A")) + def get_current_time(): + """Get current time dynamically - called each time system prompt is accessed""" + now = datetime.datetime.now() + + # Get timezone info + try: + offset = -time.timezone if not time.daylight else -time.altzone + hours = offset // 3600 + minutes = (offset % 3600) // 60 + timezone_name = f"UTC{hours:+03d}:{minutes:02d}" if minutes else f"UTC{hours:+03d}" + except Exception: + timezone_name = "UTC" + + # Chinese weekday mapping + weekday_map = { + 'Monday': '星期一', 'Tuesday': '星期二', 'Wednesday': '星期三', + 'Thursday': '星期四', 'Friday': '星期五', 'Saturday': '星期六', 'Sunday': '星期日' + } + weekday_zh = weekday_map.get(now.strftime("%A"), now.strftime("%A")) + + return { + 'time': now.strftime("%Y-%m-%d %H:%M:%S"), + 'weekday': weekday_zh, + 'timezone': timezone_name + } return { "model": conf().get("model", "unknown"), "workspace": workspace_root, "channel": conf().get("channel_type", "unknown"), - "current_time": now.strftime("%Y-%m-%d %H:%M:%S"), - "weekday": weekday_zh, - "timezone": timezone_name + "_get_current_time": get_current_time # Dynamic time function } def _migrate_config_to_env(self, workspace_root: str):