diff --git a/agentmain.py b/agentmain.py index 2b117cae..da7b37c9 100644 --- a/agentmain.py +++ b/agentmain.py @@ -55,6 +55,7 @@ class GenericAgent: self.force_non_stream = False logid = f'{(time.time_ns() + random.randrange(1_000_000)) % 1_000_000:06d}' self.log_path = os.path.join(script_dir, f'temp/model_responses/model_responses_{logid}.txt') + self.llmclient = None self.load_llm_sessions() self.extra_sys_prompts = [] self.intervene = self.extrakeyinfo = None @@ -79,20 +80,20 @@ class GenericAgent: else: llm_sessions[i] = ToolClient(mixin) except Exception as e: print(f'\n\n\n[ERROR] Failed to init MixinSession with cfg {s["mixin_cfg"]}: {e}!!!\n\n') self.llmclients = llm_sessions + if not self.llmclients: return self.llmclient = self.llmclients[self.llm_no%len(self.llmclients)] if oldhistory: self.llmclient.backend.history = oldhistory def next_llm(self, n=-1): self.load_llm_sessions() + if not self.llmclients: return self.llm_no = ((self.llm_no + 1) if n < 0 else n) % len(self.llmclients) lastc = self.llmclient self.llmclient = self.llmclients[self.llm_no] try: self.llmclient.backend.history = lastc.backend.history except: raise Exception('[ERROR] BAD Mixin config: Check your mykey.py') self.llmclient.last_tools = '' - name = self.get_llm_name(model=True) - if 'glm' in name or 'minimax' in name or 'kimi' in name: load_tool_schema('_cn') - else: load_tool_schema() + load_tool_schema() def list_llms(self): self.load_llm_sessions() return [(i, self.get_llm_name(b), i == self.llm_no) for i, b in enumerate(self.llmclients)] @@ -100,7 +101,7 @@ class GenericAgent: b = self.llmclient if b is None else b if isinstance(b, dict): return 'BADCONFIG_MIXIN' if model: return b.backend.model.lower() - return f"{type(b.backend).__name__}/{b.backend.name}" + return f"{type(b.backend).__name__.replace('Session', '')}/{b.backend.name}" def get_ctx_multiplier(self): return getattr(self.llmclient.backend, 'maxlen_multiplier', 1.0) def abort(self): diff --git a/frontends/stapp.py b/frontends/stapp.py index d9e46735..b0f3ab3d 100644 --- a/frontends/stapp.py +++ b/frontends/stapp.py @@ -15,7 +15,7 @@ import streamlit as st import time, json, re, threading, queue from datetime import timedelta import agentmain -from agentmain import GeneraticAgent +from agentmain import GenericAgent import chatapp_common # activate /continue command (monkey patches GeneraticAgent) from continue_cmd import handle_frontend_command, reset_conversation, list_sessions, extract_ui_messages from btw_cmd import handle_frontend_command as btw_handle_frontend @@ -73,19 +73,28 @@ def T(key): return I18N.get(LANG, I18N['zh']).get(key, key) @st.cache_resource def init(): - agent = GeneraticAgent() - if agent.llmclient is not None: - threading.Thread(target=agent.run, daemon=True).start() + agent = GenericAgent() + threading.Thread(target=agent.run, daemon=True).start() return agent agent = init() -if agent.llmclient is None: - _sp = getattr(agentmain, "start_subscription_portal", None) - if _sp: - _sp() - st.warning(T("reopen_page")) - else: - st.error(T("need_mykey")) +_sp = getattr(agentmain, "start_subscription_portal", None) + +@st.fragment(run_every=timedelta(seconds=2)) +def _watch_portal(): + b = st.session_state["portal_wait"] + c = tuple(n for _, n, _ in agent.list_llms()) + if c and c != b: + del st.session_state["portal_wait"] + st.session_state.pop("sidebar_llm_select", None) + st.rerun(scope="app") + +if not agent.llmclients and _sp: + st.session_state.setdefault("portal_wait", ()); _sp() +if "portal_wait" in st.session_state: _watch_portal() + +if not agent.llmclients: + st.warning(T("reopen_page")) if _sp else st.error(T("need_mykey")) st.stop() def build_prompt(objective): @@ -101,7 +110,7 @@ def build_prompt(objective): def get_controller(): b = {'ev': threading.Event(), 'obj': '', 'out': None, 'ready': False} def loop(): - ag = GeneraticAgent(); ag.verbose = False; ag.log_path = False + ag = GenericAgent(); ag.verbose = False; ag.log_path = False threading.Thread(target=ag.run, daemon=True).start() while True: b['ev'].wait(); b['ev'].clear() @@ -185,10 +194,11 @@ def render_sidebar(): st.session_state.autonomous_enabled = True st.toast("✅"); st.rerun(scope="app") st.caption(T('auto_off_cap')) - if (_sp := getattr(agentmain, "start_subscription_portal", None)): + if _sp: st.divider() if st.button(T("get_token")): - _sp(); st.toast(T("get_token_toast")) + st.session_state.portal_wait = tuple(n for _, n, _ in agent.list_llms()) + _sp(); st.rerun(scope="app") with st.sidebar: render_sidebar() def fold_turns(text): diff --git a/llmcore.py b/llmcore.py index f5340ea3..4e9d51fa 100644 --- a/llmcore.py +++ b/llmcore.py @@ -8,7 +8,8 @@ if _ROOT not in sys.path: sys.path.append(_ROOT) def _load_mykeys(): global _mykey_path try: - import mykey; importlib.reload(mykey); _mykey_path = mykey.__file__ + sys.modules.pop('mykey', None) + import mykey; _mykey_path = mykey.__file__ return {k: v for k, v in vars(mykey).items() if not k.startswith('_')} except ImportError as e: if getattr(e, 'name', None) != 'mykey': @@ -21,13 +22,15 @@ def _load_mykeys(): if isinstance(mk, dict) and 'remote_url' in mk: return requests.get(mk['remote_url'], timeout=10).json() return mk +_mykey_lock = threading.Lock() _mykey_path = _mykey_mtime = None def reload_mykeys(): global _mykey_mtime try: mt = os.stat(_mykey_path).st_mtime_ns if _mykey_path else -1 if mt == _mykey_mtime: return globals().get('mykeys', {}), False - mk = _load_mykeys(); _mykey_mtime = os.stat(_mykey_path).st_mtime_ns + with _mykey_lock: mk = _load_mykeys() + _mykey_mtime = os.stat(_mykey_path).st_mtime_ns print(f'[Info] Load mykeys from {_mykey_path}') globals().update(mykeys=mk) return mk, True @@ -1122,6 +1125,7 @@ class NativeToolClient: def resolve_session(cfg_name): cfg = reload_mykeys()[0].get(cfg_name) if not cfg: raise ValueError(f"Config '{cfg_name}' not in mykey") + cfg['_mykey_name'] = cfg_name if 'native' in cfg_name: return (NativeClaudeSession if 'claude' in cfg_name else NativeOAISession)(cfg=cfg) if 'claude' in cfg_name: return ClaudeSession(cfg=cfg) return LLMSession(cfg=cfg) if 'oai' in cfg_name else None diff --git a/memory/tmwebdriver_sop.md b/memory/tmwebdriver_sop.md index 7b0c80b4..894c23f2 100644 --- a/memory/tmwebdriver_sop.md +++ b/memory/tmwebdriver_sop.md @@ -117,7 +117,7 @@ web_execute_js script='{"cmd": "batch", "commands": [...]}' ## autofill获取与登录 检测:web_scan输出input带`data-autofilled="true"`,value显示为受保护提示(非真实值,Chrome安全保护需点击释放) - ⚠**前置条件:必须先CDP `Page.bringToFront` 切tab到前台**,Chrome仅在前台tab释放autofill保护值,后台tab物理点击无效 -- ⭐**一键释放与登录**:bringToFront → mousePressed点任一字段(无需Released,一个释放全页) → 等500ms → 补input/change事件 → 点登录 +- ⭐**最快登录(✅已验证)**:bringToFront → 无视按钮`disabled`,直接CDP完整点击登录按钮(无需处理字段);失败再兜底:mousePressed任一字段 → 等500ms → 补input/change → 点登录 ## 验证码/页面视觉截图 - ⭐首选CDP截图:`Page.captureScreenshot`(format:'png')→返回base64,无需前台/后台tab也行,全页高清