improve: fallback search, history compression refactor, tg bot stability

This commit is contained in:
Liang Jiaqing
2026-02-16 10:33:45 +08:00
parent 04833eda0e
commit 90bb6868ec
3 changed files with 45 additions and 27 deletions

19
ga.py
View File

@@ -103,8 +103,8 @@ def first_init_driver():
if len(sess) > 0: break if len(sess) > 0: break
if len(sess) == 0: return if len(sess) == 0: return
if len(sess) == 1: if len(sess) == 1:
driver.newtab() #driver.newtab()
time.sleep(5) time.sleep(3)
def web_scan(tabs_only=False, switch_tab_id=None): def web_scan(tabs_only=False, switch_tab_id=None):
""" """
@@ -207,7 +207,8 @@ def file_read(path, start=1, keyword=None, count=200, show_linenos=True):
res = list(before) + [(i, l)] + list(itertools.islice(stream, count - len(before) - 1)) res = list(before) + [(i, l)] + list(itertools.islice(stream, count - len(before) - 1))
break break
before.append((i, l)) before.append((i, l))
else: return f"Keyword '{keyword}' not found after line {start}." else: return f"Keyword '{keyword}' not found after line {start}. Falling back to content from line {start}:\n\n" \
+ file_read(path, start, None, count, show_linenos)
else: res = itertools.islice(stream, count) else: res = itertools.islice(stream, count)
return "\n".join(f"{i}|{l}" if show_linenos else l for i, l in res) return "\n".join(f"{i}|{l}" if show_linenos else l for i, l in res)
except Exception as e: except Exception as e:
@@ -287,8 +288,9 @@ class GenericAgentHandler(BaseHandler):
result = web_scan(tabs_only=tabs_only, switch_tab_id=switch_tab_id) result = web_scan(tabs_only=tabs_only, switch_tab_id=switch_tab_id)
content = result.pop("content", None) content = result.pop("content", None)
yield f'[Info] {str(result)}\n' yield f'[Info] {str(result)}\n'
if content: next_prompt = f"```html\n{content}\n```" if content: next_prompt = f"<tool_result>\n```html\n{content}\n```\n</tool_result>"
else: next_prompt = "标签页列表如上\n" else: next_prompt = "标签页列表如上\n"
# 手动tool_result为了触发历史上下文自动压缩
return StepOutcome(result, next_prompt=next_prompt) return StepOutcome(result, next_prompt=next_prompt)
def do_web_execute_js(self, args, response): def do_web_execute_js(self, args, response):
@@ -296,15 +298,16 @@ class GenericAgentHandler(BaseHandler):
支持将结果保存到文件供后续读取分析但保存功能仅限即时读取与await等异步操作不兼容。 支持将结果保存到文件供后续读取分析但保存功能仅限即时读取与await等异步操作不兼容。
''' '''
script = args.get("script", "") script = args.get("script", "")
if not script: return StepOutcome(None, next_prompt="[Error] Empty script param. Check your tool call arguments.")
save_to_file = args.get("save_to_file", "") save_to_file = args.get("save_to_file", "")
result = web_execute_js(script) result = web_execute_js(script)
if save_to_file and "js_return" in result: if save_to_file and "js_return" in result:
content = str(result["js_return"] or '') content = str(result["js_return"] or '')
abs_path = self._get_abs_path(save_to_file) abs_path = self._get_abs_path(save_to_file)
result["js_return"] = content[:200] + ("..." if len(content) > 200 else "") result["js_return"] = smart_format(content, max_str_len=200)
try: try:
with open(abs_path, 'w', encoding='utf-8') as f: f.write(str(content)) with open(abs_path, 'w', encoding='utf-8') as f: f.write(str(content))
result["js_return"] += f"\n\n[已保存以上内容到 {abs_path}]" result["js_return"] += f"\n\n[已保存完整内容到 {abs_path}]"
except: except:
result['js_return'] += f"\n\n[保存失败,无法写入文件 {abs_path}]" result['js_return'] += f"\n\n[保存失败,无法写入文件 {abs_path}]"
print("Web Execute JS Result:", smart_format(result)) print("Web Execute JS Result:", smart_format(result))
@@ -371,13 +374,15 @@ class GenericAgentHandler(BaseHandler):
if show_linenos: if show_linenos:
tips = '由于设置了show_linenos以下返回信息为(行号|)内容 。\n' tips = '由于设置了show_linenos以下返回信息为(行号|)内容 。\n'
result = tips + result result = tips + result
if ' ... [TRUNCATED]' in result:
result += '\n\n(某些行被截断,如需完整内容可改用 code_run 读取)'
next_prompt = self._get_anchor_prompt() next_prompt = self._get_anchor_prompt()
if 'memory' in path or 'sop' in path: if 'memory' in path or 'sop' in path:
next_prompt += "\nPROTOCOL: 你正在读取记忆或SOP文件若决定按sop执行请先调用相关工具提取sop中的关键点特别是靠后的进入工作记忆。" next_prompt += "\nPROTOCOL: 你正在读取记忆或SOP文件若决定按sop执行请先调用相关工具提取sop中的关键点特别是靠后的进入工作记忆。"
return StepOutcome(result, next_prompt=next_prompt) return StepOutcome(result, next_prompt=next_prompt)
def do_update_working_mem(self, args, response): def do_update_working_mem(self, args, response):
'''读取完sop后为整个任务设定后续需要临时记忆的重点。 '''为整个任务设定后续需要临时记忆的重点。
''' '''
key_info = args.get("key_info", "") key_info = args.get("key_info", "")
related_sop = args.get("related_sop", "") related_sop = args.get("related_sop", "")

View File

@@ -13,6 +13,19 @@ google_api_key = mykeys.get("google_api_key")
proxy = mykeys.get("proxy", 'http://127.0.0.1:2082') proxy = mykeys.get("proxy", 'http://127.0.0.1:2082')
proxies = {"http": proxy, "https": proxy} if proxy else None proxies = {"http": proxy, "https": proxy} if proxy else None
def compress_history_tags(messages, keep_recent=4, max_len=200):
"""Compress <thinking>/<tool_use>/<tool_result> tags in older messages to save tokens."""
for i, msg in enumerate(messages):
if i < len(messages) - keep_recent and 'orig' not in msg:
msg['orig'] = msg['prompt']
for tag in ('thinking', 'tool_use', 'tool_result'):
msg['prompt'] = re.sub(
rf'(<{tag}>)([\s\S]*?)(</{tag}>)',
lambda m, _ml=max_len: m.group(1) + (m.group(2)[:_ml] + '...') + m.group(3) if len(m.group(2)) > _ml else m.group(0),
msg['prompt']
)
return messages
class SiderLLMSession: class SiderLLMSession:
def __init__(self, default_model="gemini-3.0-flash"): def __init__(self, default_model="gemini-3.0-flash"):
from sider_ai_api import Session from sider_ai_api import Session
@@ -32,16 +45,7 @@ class ClaudeSession:
self.api_key, self.api_base, self.default_model, self.context_win = api_key, api_base.rstrip('/'), model, context_win self.api_key, self.api_base, self.default_model, self.context_win = api_key, api_base.rstrip('/'), model, context_win
self.raw_msgs, self.lock = [], threading.Lock() self.raw_msgs, self.lock = [], threading.Lock()
def _trim_messages(self, messages): def _trim_messages(self, messages):
# 压缩4轮前的assistant消息truncate <thinking>/<tool_use> 块 compress_history_tags(messages)
for i, msg in enumerate(messages):
if i < len(messages) - 4 and 'orig' not in msg:
msg['orig'] = msg['prompt']
for tag in ('thinking', 'tool_use', 'tool_result'):
msg['prompt'] = re.sub(
rf'(<{tag}>)([\s\S]*?)(</{tag}>)',
lambda m: m.group(1) + (m.group(2)[:200] + '...') + m.group(3) if len(m.group(2)) > 200 else m.group(0),
msg['prompt']
)
total = sum(len(m['prompt']) for m in messages) total = sum(len(m['prompt']) for m in messages)
if total <= self.context_win * 4: return messages if total <= self.context_win * 4: return messages
target, current, result = self.context_win * 4 * 0.9, 0, [] target, current, result = self.context_win * 4 * 0.9, 0, []
@@ -120,16 +124,9 @@ class LLMSession:
yield f"Error: {str(e)}" yield f"Error: {str(e)}"
def make_messages(self, raw_list, omit_images=True): def make_messages(self, raw_list, omit_images=True):
compress_history_tags(raw_list)
messages = [] messages = []
for i, msg in enumerate(raw_list): for i, msg in enumerate(raw_list):
if i < len(raw_list) - 4 and 'orig' not in msg:
msg['orig'] = msg['prompt']
for tag in ('thinking', 'tool_use', 'tool_result'):
msg['prompt'] = re.sub(
rf'(<{tag}>)([\s\S]*?)(</{tag}>)',
lambda m: m.group(1) + (m.group(2)[:200] + '...') + m.group(3) if len(m.group(2)) > 200 else m.group(0),
msg['prompt']
)
prompt = msg['prompt'] prompt = msg['prompt']
if omit_images and msg['image']: messages.append({"role": msg['role'], "content": "[Image omitted, if you needed it, ask me]\n" + prompt}) if omit_images and msg['image']: messages.append({"role": msg['role'], "content": "[Image omitted, if you needed it, ask me]\n" + prompt})
elif not omit_images and msg['image']: elif not omit_images and msg['image']:

View File

@@ -3,6 +3,7 @@ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from agentmain import GeneraticAgent from agentmain import GeneraticAgent
from telegram import Update from telegram import Update
from telegram.ext import ApplicationBuilder, MessageHandler, CommandHandler, filters, ContextTypes from telegram.ext import ApplicationBuilder, MessageHandler, CommandHandler, filters, ContextTypes
from telegram.request import HTTPXRequest
import mykey import mykey
agent = GeneraticAgent() agent = GeneraticAgent()
@@ -92,17 +93,32 @@ if __name__ == '__main__':
if not ALLOWED: sys.exit('ERROR: tg_allowed_users in mykey.py is empty or missing. Set it to avoid unauthorized access.') if not ALLOWED: sys.exit('ERROR: tg_allowed_users in mykey.py is empty or missing. Set it to avoid unauthorized access.')
_logf = open(os.path.join(os.path.dirname(__file__), 'temp', 'tgapp.log'), 'a', encoding='utf-8', buffering=1) _logf = open(os.path.join(os.path.dirname(__file__), 'temp', 'tgapp.log'), 'a', encoding='utf-8', buffering=1)
sys.stdout = sys.stderr = _logf sys.stdout = sys.stderr = _logf
print('[NEW] New process starting, the above are history infos ...')
threading.Thread(target=agent.run, daemon=True).start() threading.Thread(target=agent.run, daemon=True).start()
proxy = vars(mykey).get('proxy', 'http://127.0.0.1:2082') proxy = vars(mykey).get('proxy', 'http://127.0.0.1:2082')
print('proxy:', proxy) print('proxy:', proxy)
app = ApplicationBuilder().token(mykey.tg_bot_token).proxy(proxy).get_updates_proxy(proxy).build() request = HTTPXRequest(proxy=proxy, read_timeout=30, write_timeout=30, connect_timeout=30, pool_timeout=30)
app = (ApplicationBuilder()
.token(mykey.tg_bot_token)
.request(request)
.get_updates_request(request)
.build())
app.add_handler(CommandHandler("stop", cmd_abort)) app.add_handler(CommandHandler("stop", cmd_abort))
app.add_handler(CommandHandler("llm", cmd_llm)) app.add_handler(CommandHandler("llm", cmd_llm))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_msg)) app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_msg))
async def _error_handler(update, context: ContextTypes.DEFAULT_TYPE):
print(f"[{time.strftime('%m-%d %H:%M')}] TG error: {context.error}", flush=True)
app.add_error_handler(_error_handler)
print(f"TG bot starting... {time.strftime('%m-%d %H:%M')}") print(f"TG bot starting... {time.strftime('%m-%d %H:%M')}")
while True: while True:
try: try:
app.run_polling(drop_pending_updates=True) app.run_polling(
drop_pending_updates=True,
poll_interval=1.0,
timeout=30,
)
except Exception as e: except Exception as e:
print(f"[{time.strftime('%m-%d %H:%M')}] polling crashed: {e}", flush=True) print(f"[{time.strftime('%m-%d %H:%M')}] polling crashed: {e}", flush=True)
time.sleep(10) time.sleep(10)