diff --git a/ga.py b/ga.py index 1327542..d2ea7eb 100644 --- a/ga.py +++ b/ga.py @@ -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"\n```html\n{content}\n```\n" 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", "") diff --git a/sidercall.py b/sidercall.py index 0cefd2c..3bbafdd 100644 --- a/sidercall.py +++ b/sidercall.py @@ -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 // 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]*?)()', + 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 / 块 - 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]*?)()', - 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]*?)()', - 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']: diff --git a/tgapp.py b/tgapp.py index a31c7ec..211372c 100644 --- a/tgapp.py +++ b/tgapp.py @@ -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)