fix: cancel→abort, cancel_requested guard, wechatapp use turn/outputs instead of _turn_parts

This commit is contained in:
Liang Jiaqing committed 2026-05-16 18:03:51 +08:00
1 parent cebd6a37c9
commit 72d28500a3
3 files changed
+25 -27

No files matched your search

+3 -3
View File
@@ -155,17 +155,17 @@ class GenericAgent:
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:]})
'source': source, 'turn': curr_turn, 'outputs': turn_resps[-2:]})
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,
'turn': curr_turn, 'outputs': turn_resps[-1:]})
'turn': curr_turn, 'outputs': turn_resps[-2:]})
#if '</summary>' in full_resp: full_resp = full_resp.replace('</summary>', '</summary>\n\n')
#if '</file_content>' in full_resp: full_resp = re.sub(r'<file_content>\s*(.*?)\s*</file_content>', r'\n````\n<file_content>\n\1\n</file_content>\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)}")
display_queue.put({'done': full_resp + f'\n```\n{format_error(e)}\n```', 'source': source})
display_queue.put({'done': full_resp + f'\n```\n{format_error(e)}\n```', 'source': source, 'turn': curr_turn, 'outputs': turn_resps.copy()})
finally:
if self.stop_sig: print('User aborted the task.')
self.is_running = self.stop_sig = False
+8 -4
View File
@@ -173,9 +173,9 @@ class AgentManager:
raise web.HTTPNotFound(text=json.dumps({"error": f"session not found: {sid}"}, ensure_ascii=False), content_type="application/json")
if self.active_session_id == sid:
self.active_session_id = next(iter(self.sessions), None)
if sess.agent and hasattr(sess.agent, "cancel"):
if sess.agent and hasattr(sess.agent, "abort"):
with contextlib.suppress(Exception):
sess.agent.cancel()
sess.agent.abort()
emit_session_state(sess, "closed")
return {"ok": True, "sessionId": sid}
@@ -237,6 +237,10 @@ class AgentManager:
full = "GenericAgent object has no put_task/run method"
if not full:
full = "(completed)"
if sess.cancel_requested:
with self.lock:
sess.partial = None
return
with self.lock:
sess.partial = None
# Strip trailing [Info] Final response to user. marker
@@ -280,9 +284,9 @@ class AgentManager:
if not sess:
raise web.HTTPNotFound(text=json.dumps({"error": f"session not found: {sid}"}, ensure_ascii=False), content_type="application/json")
sess.cancel_requested = True
if sess.agent and hasattr(sess.agent, "cancel"):
if sess.agent and hasattr(sess.agent, "abort"):
with contextlib.suppress(Exception):
sess.agent.cancel()
sess.agent.abort()
sess.status = "cancelled"
sess.partial = None
sess.updated_at = time.time()
+14 -20
View File
@@ -298,15 +298,6 @@ def _clean(t):
t = re.sub(r'</?summary>', '', t)
return re.sub(r'\n{3,}', '\n\n', _strip_md(t)).strip()
def _turn_parts(t):
_ph = []
safe = re.sub(r'`{4,}.*?`{4,}', lambda m: (_ph.append(m.group(0)), f'\x00PH{len(_ph)-1}\x00')[1], t, flags=re.DOTALL)
parts = re.split(r'(\**LLM Running \(Turn \d+\) \.\.\.\**)', safe)
parts = [re.sub(r'\x00PH(\d+)\x00', lambda m: _ph[int(m.group(1))], p) for p in parts]
if len(parts) < 4: return [], t
turns = [parts[i] + (parts[i+1] if i+1 < len(parts) else '') for i in range(1, len(parts), 2)]
return (([parts[0]] if parts[0].strip() else []) + turns[:-1], turns[-1])
def on_message(bot, msg):
text = bot.extract_text(msg).strip()
uid = msg.get('from_user_id', '')
@@ -320,7 +311,6 @@ def on_message(bot, msg):
# Commands
if text in ('/stop', '/abort'):
agent.abort()
bot.send_text(uid, '已停止', context_token=ctx)
return
if text.startswith('/llm'):
args = text.split()
@@ -347,7 +337,7 @@ def on_message(bot, msg):
except: pass
_typing_stop.wait(2.0)
threading.Thread(target=_keep_typing, daemon=True).start()
result = ''; sent = 0; mi = 0; last_send = 0
result = ''; sent = 0; mi = 0; last_send = 0; item = {}
def _wx_send(text):
s = text.strip(); t0 = time.time()
try:
@@ -362,24 +352,28 @@ def on_message(bot, msg):
now = time.time()
if mi >= 9 or not show.strip(): return False
if mi and now - last_send < 6 * mi: return None
if _wx_send(show[:2000]): mi += 1; last_send = time.time(); return True
if _wx_send(show[:3000]): mi += 1; last_send = time.time(); return True
return False
try:
done = []; turn = 1
while True:
item = dq.get(timeout=300)
if 'done' in item: result = item['done']; break
raw = item.get('next', '')
done, partial = _turn_parts(raw)
if 'done' in item: break
if item.get('turn', turn) > turn:
outputs = item.get('outputs', [])
lastdone = outputs[-2] if len(outputs) >= 2 else ''
turn = item['turn']; done.append(lastdone)
if len(done) > sent:
merged = _clean('\n\n'.join(done[sent:]))
print(f'[WX] turns={len(done)}/{len(done)+1} sent={sent} sending={len(done)-sent}', file=sys.__stdout__)
if _send(merged):
sent = len(done)
if _send(merged): sent = len(done)
except queue.Empty: result = '[超时]'
_typing_stop.set()
done, partial = _turn_parts(result)
rest = '\n\n'.join(done[sent:] + [partial] + ['\n\n[任务已完成]'])
if rest.strip(): _wx_send((_clean(rest))[-2000:])
if 'done' in item: result, done = item['done'], item.get('outputs', [])
rest = _clean('\n\n'.join(done[sent:] + ['\n\n[任务已完成]']).strip())
if rest: _wx_send(rest[-3000:])
files = re.findall(r'\[FILE:([^\]]+)\]', result)
bad = {'filepath', '<filepath>', 'path', '<path>', 'file_path', '<file_path>', '...'}
files = [f for f in files if f.strip().lower() not in bad and (f if os.path.isabs(f) else os.path.join(_TEMP_DIR, f)) not in media_paths]