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: return
if len(sess) == 1:
driver.newtab()
time.sleep(5)
#driver.newtab()
time.sleep(3)
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))
break
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)
return "\n".join(f"{i}|{l}" if show_linenos else l for i, l in res)
except Exception as e:
@@ -287,8 +288,9 @@ class GenericAgentHandler(BaseHandler):
result = web_scan(tabs_only=tabs_only, switch_tab_id=switch_tab_id)
content = result.pop("content", None)
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"
# 手动tool_result为了触发历史上下文自动压缩
return StepOutcome(result, next_prompt=next_prompt)
def do_web_execute_js(self, args, response):
@@ -296,15 +298,16 @@ class GenericAgentHandler(BaseHandler):
支持将结果保存到文件供后续读取分析但保存功能仅限即时读取与await等异步操作不兼容。
'''
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", "")
result = web_execute_js(script)
if save_to_file and "js_return" in result:
content = str(result["js_return"] or '')
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:
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:
result['js_return'] += f"\n\n[保存失败,无法写入文件 {abs_path}]"
print("Web Execute JS Result:", smart_format(result))
@@ -371,13 +374,15 @@ class GenericAgentHandler(BaseHandler):
if show_linenos:
tips = '由于设置了show_linenos以下返回信息为(行号|)内容 。\n'
result = tips + result
if ' ... [TRUNCATED]' in result:
result += '\n\n(某些行被截断,如需完整内容可改用 code_run 读取)'
next_prompt = self._get_anchor_prompt()
if 'memory' in path or 'sop' in path:
next_prompt += "\nPROTOCOL: 你正在读取记忆或SOP文件若决定按sop执行请先调用相关工具提取sop中的关键点特别是靠后的进入工作记忆。"
return StepOutcome(result, next_prompt=next_prompt)
def do_update_working_mem(self, args, response):
'''读取完sop后为整个任务设定后续需要临时记忆的重点。
'''为整个任务设定后续需要临时记忆的重点。
'''
key_info = args.get("key_info", "")
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')
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:
def __init__(self, default_model="gemini-3.0-flash"):
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.raw_msgs, self.lock = [], threading.Lock()
def _trim_messages(self, messages):
# 压缩4轮前的assistant消息truncate <thinking>/<tool_use> 块
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']
)
compress_history_tags(messages)
total = sum(len(m['prompt']) for m in messages)
if total <= self.context_win * 4: return messages
target, current, result = self.context_win * 4 * 0.9, 0, []
@@ -120,16 +124,9 @@ class LLMSession:
yield f"Error: {str(e)}"
def make_messages(self, raw_list, omit_images=True):
compress_history_tags(raw_list)
messages = []
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']
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']:

View File

@@ -3,6 +3,7 @@ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from agentmain import GeneraticAgent
from telegram import Update
from telegram.ext import ApplicationBuilder, MessageHandler, CommandHandler, filters, ContextTypes
from telegram.request import HTTPXRequest
import mykey
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.')
_logf = open(os.path.join(os.path.dirname(__file__), 'temp', 'tgapp.log'), 'a', encoding='utf-8', buffering=1)
sys.stdout = sys.stderr = _logf
print('[NEW] New process starting, the above are history infos ...')
threading.Thread(target=agent.run, daemon=True).start()
proxy = vars(mykey).get('proxy', 'http://127.0.0.1:2082')
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("llm", cmd_llm))
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')}")
while True:
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:
print(f"[{time.strftime('%m-%d %H:%M')}] polling crashed: {e}", flush=True)
time.sleep(10)