improve: fallback search, history compression refactor, tg bot stability
This commit is contained in:
19
ga.py
19
ga.py
@@ -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", "")
|
||||||
|
|||||||
33
sidercall.py
33
sidercall.py
@@ -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']:
|
||||||
|
|||||||
20
tgapp.py
20
tgapp.py
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user