diff --git a/ga.py b/ga.py
index 4ccd84f4..0173a633 100644
--- a/ga.py
+++ b/ga.py
@@ -7,6 +7,7 @@
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from agent_loop import BaseHandler, StepOutcome, json_default
+from turn_policy import register_turn_policies
script_dir = os.path.dirname(os.path.abspath(__file__))
def code_run(code, code_type="python", timeout=60, cwd=None, code_cwd=None, stop_signal=None, maxlen=10000):
@@ -268,6 +269,8 @@ def __init__(self, parent, last_history=None, cwd='./temp'):
self.history_info = last_history if last_history else []
self.code_stop_signal = []
self._done_hooks = []
+ # Turn policy hooks - pluggable strategy chain (from turn_policy.py)
+ register_turn_policies(self)
def _get_abs_path(self, path):
if not path: return ""
@@ -543,7 +546,7 @@ def _get_anchor_prompt(self, skip=False):
try: print(prompt)
except: pass
return prompt
-
+
def turn_end_callback(self, response, tool_calls, tool_results, turn, next_prompt, exit_reason):
_c = re.sub(r'```.*?```|.*?', '', response.content, flags=re.DOTALL)
rsumm = re.search(r"(.*?)", _c, re.DOTALL)
@@ -559,15 +562,9 @@ def turn_end_callback(self, response, tool_calls, tool_results, turn, next_promp
self.history_info.append(f'[Agent] {summary}')
_plan = self._in_plan_mode()
- if turn % 75 == 0 and (not _plan):
- next_prompt += f"\n\n[DANGER] 已连续执行第 {turn} 轮。必须总结情况进行ask_user,不允许继续重试。"
- elif turn % 7 == 0:
- next_prompt += f"\n\n[DANGER] 已连续执行第 {turn} 轮。禁止无效重试。若无有效进展,必须切换策略:1. 探测物理边界 2. 请求用户协助。如有需要,可调用 update_working_checkpoint 保存关键上下文。"
- elif turn % 10 == 0: next_prompt += get_global_memory()
-
- if _plan and turn >= 10 and turn % 5 == 0:
- next_prompt = f"[Plan Hint] 正在计划模式。必须 file_read({_plan}) 确认当前步骤,回复开头引用:📌 当前步骤:...\n\n" + next_prompt
- if _plan and turn >= 120: next_prompt += f"\n\n[DANGER] Plan模式已运行 {turn} 轮,已达上限。必须 ask_user 汇报进度并确认是否继续。"
+ # Policy hook chain - each policy returns "" or a string to append
+ for policy in self._turn_policies:
+ next_prompt += policy(turn, _plan, next_prompt) or ""
injkeyinfo = consume_file(self.parent.task_dir, '_keyinfo')
injprompt = consume_file(self.parent.task_dir, '_intervene')
diff --git a/pyproject.toml b/pyproject.toml
index 8a67ca22..063b9a46 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -43,4 +43,7 @@ py-modules = []
packages = ["ga_cli"]
[project.scripts]
-ga = "ga_cli.cli:main"
\ No newline at end of file
+ga = "ga_cli.cli:main"
+
+[tool.ruff]
+exclude = ["TMWebDriver.py"]
\ No newline at end of file
diff --git a/turn_policy.py b/turn_policy.py
new file mode 100644
index 00000000..d2b51156
--- /dev/null
+++ b/turn_policy.py
@@ -0,0 +1,61 @@
+
+import os
+
+def policy_danger_ask_user(turn, _plan, next_prompt):
+ """每75轮强制ask_user(非plan模式)"""
+ if turn % 75 == 0 and (not _plan):
+ return (
+ "\n\n[DANGER] 已连续执行第 " + str(turn) + " 轮。"
+ "必须总结情况进行ask_user,不允许继续重试。"
+ )
+ return ""
+
+
+def policy_danger_retry(turn, _plan, next_prompt):
+ """每7轮禁止无效重试"""
+ if turn % 7 == 0:
+ return (
+ "\n\n[DANGER] 已连续执行第 " + str(turn) + " 轮。禁止无效重试。"
+ "若无有效进展,必须切换策略:1. 探测物理边界 "
+ "2. 请求用户协助。如有需要,可调用 update_working_checkpoint "
+ "保存关键上下文。"
+ )
+ return ""
+
+
+def policy_inject_memory(turn, _plan, next_prompt):
+ """每10轮注入全局记忆"""
+ if turn % 10 == 0:
+ from ga import get_global_memory
+ return get_global_memory()
+ return ""
+
+
+def policy_plan_limit(turn, _plan, next_prompt):
+ """Plan模式上限检测"""
+ if _plan and turn >= 10 and turn % 5 == 0 and turn <= 110:
+ return (
+ "[Plan Hint] 正在计划模式。必须 file_read(" + str(_plan) + ") "
+ "确认当前步骤,回复开头引用:当前步骤:...\n\n"
+ )
+ if _plan and turn >= 120:
+ return (
+ "\n\n[DANGER] Plan模式已运行 " + str(turn) + " 轮,已达上限。"
+ "必须 ask_user 汇报进度并确认是否继续。"
+ )
+ return ""
+
+# Default turn policies that ship with the agent
+DEFAULT_TURN_POLICIES = [
+ policy_danger_ask_user,
+ policy_danger_retry,
+ policy_inject_memory,
+ policy_plan_limit,
+]
+
+def register_turn_policies(handler, policies=None):
+ """Register turn policies onto a GenericAgentHandler instance.
+ """
+ if policies is None:
+ policies = DEFAULT_TURN_POLICIES
+ handler._turn_policies = list(policies)