From cebd6a37c9da8edac3d85b03f868fc40b9e4ba6d Mon Sep 17 00:00:00 2001 From: Liang Jiaqing Date: Sat, 16 May 2026 17:13:42 +0800 Subject: [PATCH] agentloop yield turn dict marker; agentmain intercepts and tracks per-turn outputs --- agent_loop.py | 6 ++++-- agentmain.py | 28 ++++++++++++++++------------ frontends/stapp.py | 7 ++----- ga.py | 4 ++-- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/agent_loop.py b/agent_loop.py index 768d4320..3011735f 100644 --- a/agent_loop.py +++ b/agent_loop.py @@ -39,7 +39,8 @@ def get_pretty_json(data): data = data.copy(); data["script"] = data["script"].replace("; ", ";\n ") return json.dumps(data, indent=2, ensure_ascii=False).replace('\\n', '\n') -def agent_runner_loop(client, system_prompt, user_input, handler, tools_schema, max_turns=40, verbose=True, initial_user_content=None): +def agent_runner_loop(client, system_prompt, user_input, handler, tools_schema, + max_turns=40, verbose=True, initial_user_content=None, yield_info=False): messages = [ {"role": "system", "content": system_prompt}, {"role": "user", "content": initial_user_content if initial_user_content is not None else user_input} @@ -49,8 +50,9 @@ def agent_runner_loop(client, system_prompt, user_input, handler, tools_schema, turn += 1; turnstr = f'LLM Running (Turn {turn}) ...' if handler.parent.task_dir: turnstr = f'Turn {turn} ...' if verbose: turnstr = f'**{turnstr}**' + if yield_info: yield {'turn': turn} yield f"\n\n{turnstr}\n\n" - if turn%10 == 0: client.last_tools = '' # 每10轮重置一次工具描述,避免上下文过大导致的模型性能下降 + if turn%10 == 0: client.last_tools = '' # 每10轮重置一次工具描述 response_gen = client.chat(messages=messages, tools=tools_schema) if verbose: response = yield from response_gen diff --git a/agentmain.py b/agentmain.py index 6cd7aab8..c488efa7 100644 --- a/agentmain.py +++ b/agentmain.py @@ -46,8 +46,8 @@ class GenericAgent: self.task_dir = None self.history = []; self.handler = None; self.task_queue = queue.Queue() - self.is_running = False; self.stop_sig = False - self.llm_no = 0; self.inc_out = False; self.verbose = True + self.is_running = False; self.stop_sig = False; self.llm_no = 0; + self.inc_out = False; self.verbose = True; self.show_mode = 'text' self.peer_hint = True self.log_path = os.path.join(script_dir, f'temp/model_responses/model_responses_{int(time.time()*1e6)%1000000:06d}.txt') self.load_llm_sessions() @@ -143,21 +143,25 @@ class GenericAgent: if ps > 0: handler.working['key_info'] += f'\n[SYSTEM] 此为 {ps} 个对话前设置的key_info,若已在新任务,先更新或清除工作记忆。\n' self.handler = handler # although new handler, the **full** history is in llmclient, so it is full history! self.llmclient.log_path = self.log_path - gen = agent_runner_loop(self.llmclient, sys_prompt, raw_query, - handler, TOOLS_SCHEMA, max_turns=70, verbose=self.verbose) + gen = agent_runner_loop(self.llmclient, sys_prompt, raw_query, handler, TOOLS_SCHEMA, + max_turns=80, verbose=self.verbose, yield_info=True) try: - full_resp = ""; last_pos = 0 + full_resp = ""; last_pos = 0; curr_turn = 0; turn_resps = [] for chunk in gen: if consume_file(self.task_dir, '_stop'): self.abort() if self.stop_sig: break - full_resp += chunk - if len(full_resp) - last_pos > 50 or 'LLM Running' in chunk: - display_queue.put({'next': full_resp[last_pos:] if self.inc_out else full_resp, 'source': source}) + if isinstance(chunk, dict) and 'turn' in chunk: + curr_turn = chunk['turn']; turn_resps.append(''); continue + full_resp += chunk; turn_resps[-1] += chunk + if len(full_resp) - last_pos > 30 or 'LLM Running' in chunk: + display_queue.put({'next': full_resp[last_pos:] if self.inc_out else full_resp, + 'source': source, 'turn': curr_turn, 'outputs': turn_resps[-1:]}) last_pos = len(full_resp) - if self.inc_out and last_pos < len(full_resp): display_queue.put({'next': full_resp[last_pos:], 'source': source}) - if '' in full_resp: full_resp = full_resp.replace('', '\n\n') - if '' in full_resp: full_resp = re.sub(r'\s*(.*?)\s*', r'\n````\n\n\1\n\n````', full_resp, flags=re.DOTALL) - display_queue.put({'done': full_resp, 'source': source}) + if self.inc_out and last_pos < len(full_resp): display_queue.put({'next': full_resp[last_pos:], 'source': source, + 'turn': curr_turn, 'outputs': turn_resps[-1:]}) + #if '' in full_resp: full_resp = full_resp.replace('', '\n\n') + #if '' in full_resp: full_resp = re.sub(r'\s*(.*?)\s*', r'\n````\n\n\1\n\n````', full_resp, flags=re.DOTALL) + display_queue.put({'done': full_resp, 'source': source, 'turn': curr_turn, 'outputs': turn_resps.copy()}) self.history = handler.history_info except Exception as e: print(f"Backend Error: {format_error(e)}") diff --git a/frontends/stapp.py b/frontends/stapp.py index 83a6d33c..0b5e2639 100644 --- a/frontends/stapp.py +++ b/frontends/stapp.py @@ -281,11 +281,8 @@ if prompt := st.chat_input("any task?"): result = handle_frontend_command(agent, cmd) history = extract_ui_messages(target) if target and result.startswith('✅') else None tail = [{"role": "assistant", "content": result, "time": ts}] - if history: - st.session_state.messages = history + tail - else: - st.session_state.messages = list(st.session_state.messages) + \ - [{"role": "user", "content": cmd, "time": ts}] + tail + if history: st.session_state.messages = history + tail + else: st.session_state.messages = list(st.session_state.messages)+[{"role": "user", "content": cmd, "time": ts}]+tail _reset_and_rerun() if cmd.startswith("/btw"): answer = btw_handle_frontend(agent, cmd) # sync; bypasses put_task → main agent.run() untouched diff --git a/ga.py b/ga.py index c2e5681d..0178c0d8 100644 --- a/ga.py +++ b/ga.py @@ -558,7 +558,7 @@ class GenericAgentHandler(BaseHandler): self.history_info.append(f'[Agent] {summary}') _plan = self._in_plan_mode() - if turn % 65 == 0 and (not _plan): + 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 保存关键上下文。" @@ -566,7 +566,7 @@ class GenericAgentHandler(BaseHandler): 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 >= 90: next_prompt += f"\n\n[DANGER] Plan模式已运行 {turn} 轮,已达上限。必须 ask_user 汇报进度并确认是否继续。" + if _plan and turn >= 120: next_prompt += f"\n\n[DANGER] Plan模式已运行 {turn} 轮,已达上限。必须 ask_user 汇报进度并确认是否继续。" injkeyinfo = consume_file(self.parent.task_dir, '_keyinfo') injprompt = consume_file(self.parent.task_dir, '_intervene')