refactor: unify docstrings, add /resume command, simplify error msg
This commit is contained in:
@@ -17,13 +17,14 @@ def load_tool_schema(suffix=''):
|
|||||||
TOOLS_SCHEMA = json.loads(TS if os.name == 'nt' else TS.replace('powershell', 'bash'))
|
TOOLS_SCHEMA = json.loads(TS if os.name == 'nt' else TS.replace('powershell', 'bash'))
|
||||||
load_tool_schema()
|
load_tool_schema()
|
||||||
|
|
||||||
|
lang_suffix = '_en' if os.environ.get('GA_LANG', '') == 'en' else ''
|
||||||
mem_dir = os.path.join(script_dir, 'memory')
|
mem_dir = os.path.join(script_dir, 'memory')
|
||||||
if not os.path.exists(mem_dir): os.makedirs(mem_dir)
|
if not os.path.exists(mem_dir): os.makedirs(mem_dir)
|
||||||
mem_txt = os.path.join(mem_dir, 'global_mem.txt')
|
mem_txt = os.path.join(mem_dir, 'global_mem.txt')
|
||||||
if not os.path.exists(mem_txt): open(mem_txt, 'w', encoding='utf-8').write('# [Global Memory - L2]\n')
|
if not os.path.exists(mem_txt): open(mem_txt, 'w', encoding='utf-8').write('# [Global Memory - L2]\n')
|
||||||
mem_insight = os.path.join(mem_dir, 'global_mem_insight.txt')
|
mem_insight = os.path.join(mem_dir, 'global_mem_insight.txt')
|
||||||
if not os.path.exists(mem_insight):
|
if not os.path.exists(mem_insight):
|
||||||
t = os.path.join(script_dir, 'assets/global_mem_insight_template.txt')
|
t = os.path.join(script_dir, f'assets/global_mem_insight_template{lang_suffix}.txt')
|
||||||
open(mem_insight, 'w', encoding='utf-8').write(open(t, encoding='utf-8').read() if os.path.exists(t) else '')
|
open(mem_insight, 'w', encoding='utf-8').write(open(t, encoding='utf-8').read() if os.path.exists(t) else '')
|
||||||
cdp_cfg = os.path.join(script_dir, 'assets/tmwd_cdp_bridge/config.js')
|
cdp_cfg = os.path.join(script_dir, 'assets/tmwd_cdp_bridge/config.js')
|
||||||
if not os.path.exists(cdp_cfg):
|
if not os.path.exists(cdp_cfg):
|
||||||
@@ -33,8 +34,7 @@ if not os.path.exists(cdp_cfg):
|
|||||||
except Exception as e: print(f'[WARN] CDP config init failed: {e} — advanced web features (tmwebdriver) will be unavailable.')
|
except Exception as e: print(f'[WARN] CDP config init failed: {e} — advanced web features (tmwebdriver) will be unavailable.')
|
||||||
|
|
||||||
def get_system_prompt():
|
def get_system_prompt():
|
||||||
suffix = '_en' if os.environ.get('GA_LANG', '') == 'en' else ''
|
with open(os.path.join(script_dir, f'assets/sys_prompt{lang_suffix}.txt'), 'r', encoding='utf-8') as f: prompt = f.read()
|
||||||
with open(os.path.join(script_dir, f'assets/sys_prompt{suffix}.txt'), 'r', encoding='utf-8') as f: prompt = f.read()
|
|
||||||
prompt += f"\nToday: {time.strftime('%Y-%m-%d %a')}\n"
|
prompt += f"\nToday: {time.strftime('%Y-%m-%d %a')}\n"
|
||||||
prompt += get_global_memory()
|
prompt += get_global_memory()
|
||||||
return prompt
|
return prompt
|
||||||
@@ -111,6 +111,8 @@ class GeneraticAgent:
|
|||||||
setattr(self.llmclient.backend, k, v)
|
setattr(self.llmclient.backend, k, v)
|
||||||
display_queue.put({'done': f"✅ session.{k} = {v!r}"})
|
display_queue.put({'done': f"✅ session.{k} = {v!r}"})
|
||||||
self.task_queue.task_done(); continue
|
self.task_queue.task_done(); continue
|
||||||
|
if raw_query.strip() == '/resume':
|
||||||
|
raw_query = '简单看看model_responses中的最近几次对话结尾部分(除了本次),分别简单总结一下让我选择,然后你简单阅读了解情况后作为我们接下来聊天的基础'
|
||||||
self.is_running = True
|
self.is_running = True
|
||||||
rquery = smart_format(raw_query.replace('\n', ' '), max_str_len=200)
|
rquery = smart_format(raw_query.replace('\n', ' '), max_str_len=200)
|
||||||
self.history.append(f"[USER]: {rquery}")
|
self.history.append(f"[USER]: {rquery}")
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ st.set_page_config(page_title="Cowork", layout="wide")
|
|||||||
def init():
|
def init():
|
||||||
agent = GeneraticAgent()
|
agent = GeneraticAgent()
|
||||||
if agent.llmclient is None:
|
if agent.llmclient is None:
|
||||||
st.error("⚠️ 未配置任何可用的 LLM 接口,请在 mykey.py 中添加 sider_cookie 或 oai_apikey+oai_apibase 等信息后重启。")
|
st.error("⚠️ 未配置任何可用的 LLM 接口,请设置mykey.py。")
|
||||||
st.stop()
|
st.stop()
|
||||||
else: threading.Thread(target=agent.run, daemon=True).start()
|
else: threading.Thread(target=agent.run, daemon=True).start()
|
||||||
return agent
|
return agent
|
||||||
|
|||||||
35
ga.py
35
ga.py
@@ -12,8 +12,7 @@ def code_run(code, code_type="python", timeout=60, cwd=None, code_cwd=None, stop
|
|||||||
"""代码执行器
|
"""代码执行器
|
||||||
python: 运行复杂的 .py 脚本(文件模式)
|
python: 运行复杂的 .py 脚本(文件模式)
|
||||||
powershell/bash: 运行单行指令(命令模式)
|
powershell/bash: 运行单行指令(命令模式)
|
||||||
优先使用python,仅在必要系统操作时使用powershell。
|
优先使用python,仅在必要系统操作时使用powershell"""
|
||||||
"""
|
|
||||||
preview = (code[:60].replace('\n', ' ') + '...') if len(code) > 60 else code.strip()
|
preview = (code[:60].replace('\n', ' ') + '...') if len(code) > 60 else code.strip()
|
||||||
yield f"[Action] Running {code_type} in {os.path.basename(cwd)}: {preview}\n"
|
yield f"[Action] Running {code_type} in {os.path.basename(cwd)}: {preview}\n"
|
||||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
@@ -90,9 +89,8 @@ def code_run(code, code_type="python", timeout=60, cwd=None, code_cwd=None, stop
|
|||||||
if code_type == "python" and tmp_path and os.path.exists(tmp_path): os.remove(tmp_path)
|
if code_type == "python" and tmp_path and os.path.exists(tmp_path): os.remove(tmp_path)
|
||||||
|
|
||||||
|
|
||||||
def ask_user(question: str, candidates: list = None):
|
def ask_user(question, candidates=None):
|
||||||
"""question: 向用户提出的问题。candidates: 可选的候选项列表。需要保证should_exit为True
|
"""question: 向用户提出的问题。candidates: 可选的候选项列表"""
|
||||||
"""
|
|
||||||
return {"status": "INTERRUPT", "intent": "HUMAN_INTERVENTION",
|
return {"status": "INTERRUPT", "intent": "HUMAN_INTERVENTION",
|
||||||
"data": {"question": question, "candidates": candidates or []}}
|
"data": {"question": question, "candidates": candidates or []}}
|
||||||
|
|
||||||
@@ -165,21 +163,7 @@ def log_memory_access(path):
|
|||||||
with open(stats_file, 'w', encoding='utf-8') as f: json.dump(stats, f, indent=2, ensure_ascii=False)
|
with open(stats_file, 'w', encoding='utf-8') as f: json.dump(stats, f, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
def web_execute_js(script, switch_tab_id=None, no_monitor=False):
|
def web_execute_js(script, switch_tab_id=None, no_monitor=False):
|
||||||
"""
|
"""执行 JS 脚本来控制浏览器,并捕获结果和页面变化"""
|
||||||
执行 JS 脚本来控制浏览器,并捕获结果和页面变化。
|
|
||||||
script: 要执行的 JavaScript 代码字符串。
|
|
||||||
return {
|
|
||||||
"status": "failed" if error_msg else "success",
|
|
||||||
"js_return": result,
|
|
||||||
"error": error_msg,
|
|
||||||
"transients": transients,
|
|
||||||
"environment": {
|
|
||||||
"newTabs": [],
|
|
||||||
"reloaded": reloaded
|
|
||||||
},
|
|
||||||
"diff": diff_summary,
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
global driver
|
global driver
|
||||||
try:
|
try:
|
||||||
if driver is None: first_init_driver()
|
if driver is None: first_init_driver()
|
||||||
@@ -187,13 +171,12 @@ def web_execute_js(script, switch_tab_id=None, no_monitor=False):
|
|||||||
if switch_tab_id: driver.default_session_id = switch_tab_id
|
if switch_tab_id: driver.default_session_id = switch_tab_id
|
||||||
result = simphtml.execute_js_rich(script, driver, no_monitor=no_monitor)
|
result = simphtml.execute_js_rich(script, driver, no_monitor=no_monitor)
|
||||||
return result
|
return result
|
||||||
except Exception as e:
|
except Exception as e: return {"status": "error", "msg": format_error(e)}
|
||||||
return {"status": "error", "msg": format_error(e)}
|
|
||||||
|
|
||||||
def expand_file_refs(text, base_dir=None):
|
def expand_file_refs(text, base_dir=None):
|
||||||
"""展开文本中的 {{file:路径:起始行:结束行}} 引用为实际文件内容。
|
"""展开文本中的 {{file:路径:起始行:结束行}} 引用为实际文件内容。
|
||||||
可与普通文本混排。展开失败抛 ValueError。
|
可与普通文本混排。展开失败抛 ValueError。
|
||||||
base_dir: 相对路径的基准目录,默认为进程 cwd。"""
|
base_dir: 相对路径的基准目录,默认为进程 cwd"""
|
||||||
pattern = r'\{\{file:(.+?):(\d+):(\d+)\}\}'
|
pattern = r'\{\{file:(.+?):(\d+):(\d+)\}\}'
|
||||||
def replacer(match):
|
def replacer(match):
|
||||||
path, start, end = match.group(1), int(match.group(2)), int(match.group(3))
|
path, start, end = match.group(1), int(match.group(2)), int(match.group(3))
|
||||||
@@ -205,8 +188,7 @@ def expand_file_refs(text, base_dir=None):
|
|||||||
return re.sub(pattern, replacer, text)
|
return re.sub(pattern, replacer, text)
|
||||||
|
|
||||||
def file_patch(path: str, old_content: str, new_content: str):
|
def file_patch(path: str, old_content: str, new_content: str):
|
||||||
"""在文件中寻找唯一的 old_content 块并替换为 new_content。
|
"""在文件中寻找唯一的 old_content 块并替换为 new_content"""
|
||||||
"""
|
|
||||||
path = str(Path(path).resolve())
|
path = str(Path(path).resolve())
|
||||||
try:
|
try:
|
||||||
if not os.path.exists(path): return {"status": "error", "msg": "文件不存在"}
|
if not os.path.exists(path): return {"status": "error", "msg": "文件不存在"}
|
||||||
@@ -218,8 +200,7 @@ def file_patch(path: str, old_content: str, new_content: str):
|
|||||||
updated_text = full_text.replace(old_content, new_content)
|
updated_text = full_text.replace(old_content, new_content)
|
||||||
with open(path, 'w', encoding='utf-8') as f: f.write(updated_text)
|
with open(path, 'w', encoding='utf-8') as f: f.write(updated_text)
|
||||||
return {"status": "success", "msg": "文件局部修改成功"}
|
return {"status": "success", "msg": "文件局部修改成功"}
|
||||||
except Exception as e:
|
except Exception as e: return {"status": "error", "msg": str(e)}
|
||||||
return {"status": "error", "msg": str(e)}
|
|
||||||
|
|
||||||
_read_dirs = set()
|
_read_dirs = set()
|
||||||
def _scan_files(base, depth=2):
|
def _scan_files(base, depth=2):
|
||||||
|
|||||||
Reference in New Issue
Block a user