Commit Graph
1263 Commits
Author SHA1 Message Date
LJQ 20eebe7441 Merge pull request #671 from dd3xp/main
Merge desktop fork updates into upstream main
2026-07-14 21:33:44 +08:00
Kailigithub 425ec1a02e fix(tmwebdriver): wrap prints in safe_print to survive stdout revoke (#673)
When OS revokes master stdout, bare print() raises BrokenPipeError and aborts WS handle before tab registration, causing stale web_scan data and extension reconnect loops. Mirror ga.py safe_print across TMWebDriver log sites.

Closes #672
2026-07-14 20:11:55 +08:00
dd3xp 3a30cda63c release desktop portable v0.1.6 2026-07-14 00:54:32 -04:00
dd3xp 5887450e6a Merge upstream main into desktop main 2026-07-14 00:47:12 -04:00
dd3xp a10378b563 improve settings feature descriptions 2026-07-14 00:31:10 -04:00
dd3xp 58cb4cdc7c fix desktop empty turn handling 2026-07-13 23:50:14 -04:00
Shen HaoandShen Hao d1d517f374 fix(slash_cmds): /update pins git commands to the repo root (#681)
The agent's default cwd is the temp/ subdirectory, where git resolves
'-- <file>' pathspecs relative to cwd. Fed the root-relative paths that
'git diff --name-only' prints, 'git checkout upstream/main -- <file>'
fails with "pathspec did not match", breaking the working-tree
reconcile steps of /update. The prompt now tells the agent to run every
git command from the repo root (_ROOT), in both EN and ZH.

Co-authored-by: Shen Hao <shenhao-stu@users.noreply.github.com>
2026-07-13 19:28:03 +08:00
Jiaqing Liang 5b0b8ead6e chore: stop tracking local model instruction files
Ignore assets/glm52_instruction.txt and assets/gpt55_instruction.txt
so local customizations stay out of the repo.
2026-07-13 17:00:59 +08:00
Jiaqing Liang 0700e57597 feat: add trim_keep_prefix to keep leading messages on hard trim
Hard-delete path can preserve the first K history messages, insert a "..." gap, and strip dangling tool_use at the cut. Default 0 keeps previous behavior.
2026-07-13 16:03:40 +08:00
Jiaqing Liang 5e31b4d59a docs(project_mode): clarify cwd is ./temp to avoid nested temp/ paths 2026-07-13 15:11:43 +08:00
Liang Jiaqing b298cc1b72 refactor: make MixinSession a routed session facade 2026-07-13 11:30:13 +08:00
Liang Jiaqing 8553e98723 feat: scale tool-output limits with context_win
Add maxlen_multiplier derived from context_win (capped 3x); drives per-tool
truncation caps and history compression interval. WebScan uses half-increment
growth to avoid saturating its 35000 base. Docs updated for the new coupling.
2026-07-13 09:55:52 +08:00
Liang Jiaqing d910b689be rename verify_sop -> deliverable_audit_sop (避免名字过宽导致主agent小任务误触发验证审计SOP); ga.py: file_patch/file_write 保持原文件换行符, 修复LF文件被污染成CRLF; _arg 类型强转修复字符串false等 2026-07-12 15:09:34 +08:00
Liang Jiaqing 3a315f3e1c Fix Python compatibility and tune checkpoint intervals 2026-07-11 22:05:05 +08:00
LJQ 1c4f9ffc7b Merge pull request #679 from shenhao-stu/fix/update-prompt-overlay-merge
fix(slash_cmds): merge additive-overlay files (e.g. .gitignore) on /update
2026-07-11 10:20:34 +08:00
Shen Hao 8395962197 fix(slash_cmds): merge additive-overlay files on /update, simplify prompt
The /update prompt reconciles the working tree "upstream-first" file by
file. That silently drops fork-local additions to files BOTH sides edit —
most painfully .gitignore, whose local ignore rules vanish, so a fork's
private dirs resurface as untracked noise (and can get committed by
accident).

Treat files carrying a `Fork-only local overlay` marker (e.g. .gitignore)
as a MERGE: take upstream as the base, then re-append everything under the
marker verbatim, and verify the marker survived. Along the way, tighten
both the EN and ZH prompts (75 -> 58 lines) without dropping any operative
step.
2026-07-11 01:39:54 +08:00
Liang Jiaqing 14c7734f5a Allow max OpenAI reasoning effort 2026-07-10 22:27:19 +08:00
nianyucatfish be90c8d2d3 fix(tui-v2): detach tool subprocess stdin (#678) 2026-07-10 22:25:54 +08:00
nianyucatfish cdc2a3abeb fix(continue): hide archived orphan worldlines (#677) 2026-07-10 22:25:11 +08:00
yanghang eacd3d176d Merge remote-tracking branch 'upstream/main' into merge-upstream-main-20260710 2026-07-10 18:56:03 +08:00
yanghang 409ad66551 fix(desktop): load conductor IM plugins from external core 2026-07-10 18:35:36 +08:00
yanghang 01cd579326 chore(desktop): drop local shell design note 2026-07-10 17:43:09 +08:00
yanghang 3821e71b8a fix(desktop): accept external core without desktop bridge 2026-07-10 17:39:39 +08:00
Liang Jiaqing 9d99e9fc74 fix: isolate project mode per agent instance 2026-07-10 17:31:52 +08:00
Liang Jiaqing 3f6fb9c63b fix: persist UI history and retain recent L4 sessions 2026-07-10 14:56:36 +08:00
Liang Jiaqing 8ea8807ced Improve session controls and compact LLM logs 2026-07-10 11:40:22 +08:00
yiqi-017 8ea039724f feat(desktop): thin-shell over external core via GA_ROOT (方案三)
Run the bundle's own bridge + frontend but drive an external GenericAgent
核 injected via GA_ROOT, instead of swapping to the external bridge or
copying files into 本体. New UI + external核/data, no mutation, logs
naturally unified with the核's other frontends.

- desktop_bridge.py: find_default_ga_root() honors --ga-root / GA_ROOT
  (validated), else derives as before; conductor now spawned from the
  BUNDLE (APP_DIR/conductor.py) with GA_ROOT in env; scheduler stays核-side
- conductor.py: ROOT prefers GA_ROOT env, else own-path derivation
- lib.rs: override no longer changes project_dir (always bundle bridge);
  sanitize_bundle_env injects GA_ROOT; takeover compares effective ga_root;
  set_ga_source drops file-copy sync and instead runs a contract probe
  before committing; removed copy_dir_all/sync_desktop_files
- ga_contract_probe.py (new): subprocess, introspect-only (no GenericAgent
  instantiation) symbol/signature check of the核's bridge/conductor/
  cost_tracker contract; doubles as a dependency check
- GA桌面壳-参考方案.md: plan + feasibility review + probe checklist
2026-07-10 09:53:21 +08:00
yiqi-017 17b87f1c6a Merge origin/main into main 2026-07-09 22:49:05 +08:00
yiqi-017 377e437d85 Merge branch 'yiqi_source_sync' into main
On connect-to-source, push the shell's own (new) desktop files into the
本体 (backing up its originals) before restarting the bridge, so it
serves the new frontend + bridge while keeping the 本体 agent/data.
2026-07-09 22:45:43 +08:00
Liang Jiaqing a195bdc101 Handle Claude refusal without retry 2026-07-09 13:45:43 +08:00
dd3xp ea4bf591cb docs: mention Windows Defender loopback issue 2026-07-08 00:47:24 -04:00
yiqi-017 da5fbef965 feat(desktop): sync shell desktop files into 本体 on connect
When connecting to a separate GA source (design A), the bridge and the
served frontend come from that 本体 — so an older 本体 showed an old
desktop UI. set_ga_source now pushes this shell's own (new) desktop
files into the 本体 before restarting the bridge, so it serves the new
UI + bridge while keeping the 本体 agent/data.

- copy_dir_all + sync_desktop_files: back up 本体 originals into
  temp/desktop_sync_backup_<ts>/, then copy the shell version over
- synced set: frontends/desktop/static/, desktop_bridge.py,
  plan_state.py, cost_tracker.py (NOT src-tauri / build artifacts)
- skipped when the source is the shell's own code location (dev tree)
2026-07-08 00:55:09 +08:00
dd3xp dd174cfd01 Merge origin/main into main 2026-07-07 10:37:48 -04:00
bcda218cda chore: update WeChat group QR code (#670)
Replace the existing GenericAgent experience group QR image with the latest version while keeping the same filename and README reference intact.

Co-authored-by: Shen Hao <shenhao-stu@users.noreply.github.com>
Co-authored-by: GenericAgent <bot@gaagent.ai>
2026-07-07 20:56:59 +08:00
yanghang 40efb4412d fix(desktop): statically link MSVC CRT into the Windows exe
GenericAgent.exe linked the Universal CRT dynamically, so on stripped/older
Windows images the shell itself could fail to load before the (already
UCRT-bundled) embedded python ever ran. Enable +crt-static via a
target-scoped .cargo/config.toml — macOS/Linux builds never read the
x86_64-pc-windows-msvc section. Verified locally: built exe imports no
api-ms-win-crt-*/vcruntime140/ucrtbase (kernel32 control present).
2026-07-07 20:00:53 +08:00
yanghang 86615d4f1e fix(desktop): capture installer stderr/stdout tail in prepare errors
run_offline_prepare discarded the script's stderr (Stdio::null) and only
parsed stdout for progress markers, so a failed install surfaced nothing
but 'prepare exited with status Some(N)'. Pipe stderr (drained on a helper
thread to avoid pipe-buffer deadlock), keep the last 40 lines of each
stream, and append them to the error shown in the setup window and written
to prepare_error.log — the actual pip failure is now visible.
2026-07-07 19:47:29 +08:00
yanghang f34cbe633a Merge fix/desktop-i18n-prepare-error-ucrt into main
- restore corrupted zh i18n (loading/setup blocks)
- surface first-run prepare errors in the setup window + prepare_error.log
- bundle app-local UCRT in the Windows portable package
- restore memory/import rpc case lost in merge 8bb91aa
2026-07-07 19:29:06 +08:00
yanghang 66843bef44 chore(desktop): bump app.js cache version for memory/import rpc fix 2026-07-07 19:00:52 +08:00
Liang Jiaqing 15853775c9 Add model extra system prompt config support 2026-07-07 18:52:35 +08:00
yanghang 716b22f97e fix(desktop): restore memory/import rpc case lost in merge 8bb91aa
The 8bb91aa merge (RoundSquisheen UI rewrite x main) resolved app.js by
dropping exactly one rpc dispatcher case — 'memory/import' — while keeping
the importMemory caller and the settings button. Result: clicking import
always threw 'Unknown RPC method: memory/import'. Re-add the case; the
bridge endpoint (POST /memory/import) was never lost.
2026-07-07 18:45:01 +08:00
abraxas914 79366ea6fb Merge pull request #21 from abraxas914/fix/conductor-error-feedback
fix(conductor): push error to frontend on LLM failure
2026-07-07 16:48:47 +08:00
abraxas914 3219fc1806 fix(conductor): push error chat to frontend when LLM call fails
When all LLM nodes timeout/fail, the conductor's except block only
printed to stdout — users saw their message disappear with no feedback.
Now broadcasts a role="error" chat item via the existing WebSocket
pipeline so the frontend renders a red error bubble inline.
2026-07-07 16:46:03 +08:00
yanghang 4799271943 fix(desktop): restore corrupted zh i18n, surface prepare errors, bundle UCRT
- i18n.js: the zh block (loading.*/setup.*) shipped with every Chinese
  character mangled into literal '?' (a non-UTF-8 save when the file was
  first added in 1bcb41d). Restore all 22 keys from the intact en block.
- Surface first-run prepare failures instead of silently opening the setup
  window: store the error, expose it via get_prepare_error, show it in
  fallback.html, and write runtime/prepare_error.log.
- Windows CI: deploy app-local UCRT (api-ms-win-crt-*.dll + ucrtbase.dll
  from the SDK redist) next to the embedded python so python.exe loads on
  images lacking an in-box Universal CRT. Pure SDK source, hard-fail if absent.
2026-07-07 15:28:30 +08:00
nianyucatfish 14d8df3ddd feat(worldline): persistent checkpoint-tree rewind for tui_v2 (/rewind + /worldline) (#667)
* feat(worldline): integrate checkpoint-tree rewind into tui_v2

- tuiapp_v2.py: /rewind durable inline picker + /worldline three-pane
  checkpoint tree (tree UI inlined; colors follow the v2 theme) with a
  per-node diff viewport; conv-only /rewind restores via the persistent store.
- worldline.py (new): UI-agnostic backend — RewindStore (persistent
  checkpoint tree + content-addressed blobs), reconcile, restore_plan,
  node_diff, native-log projection.
- continue_cmd.py: gated worldline support — list_sessions(rewind_root=),
  continue_inplace/copy(allow_empty=); default-off, other UIs byte-identical.
- tui_v3.py: status line shows concrete model id (unrelated minor tweak).

* feat(worldline): /rewind reuses the restore-mode picker (conv/code/both)

After picking a turn, /rewind now opens the same RestoreModeScreen as
/worldline to choose conversation / code / both, then restores via the
persistent store — making /rewind a true lite view of /worldline (linear
list, no tree/diff) over the identical restore backend.

* feat(worldline): sync working memory (history_info/key_info) on rewind

树节点除 conv 外,再存 history_info 增量(与 conv 同构)+ key_info 快照。
restore_plan 重建二者,_rw_sync_working_memory 在 rewind 时就地写回
handler.history_info / working['key_info'],使注入的 WORKING MEMORY 与
回退后的对话一致,消除旧 rewind「历史回退、纪要串味」缺陷。

向后兼容:老树无 WM 记录 → path_has_wm=False → 恢复时跳过 WM 同步,
不动现场纪要。单测 21/21 + 真机(363580)端到端验证(call_013→014
v2 痕迹 ×3→×0)通过。

* fix(worldline): reconcile against the log, only on /continue; rebuild working memory on absorb

- reconcile now takes the log-parsed full history, never the compressed
  backend.history. Compressed memory is a lossy derivative; reconciling the
  full tree against it made the tree adopt a front-trimmed suffix as a new
  trunk (false divergence). Contract pinned in the docstring.
- drop in-session reconcile from /rewind and /worldline: the tree is kept
  current every turn by _rw_commit, and live history there is compressed.
  reconcile now runs only on /continue, where backend.history is the freshly
  loaded full log.
- reconcile rebuilds history_info/key_info from the absorbed log so resumed
  and external-UI sessions also carry working memory on rewind.

* fix(worldline): feed commit the full log; derive deltas from the tree's real length

_rw_commit fed the compressed backend.history, so once a long session front-trims,
commit's absolute hist_len delta drops turns. Now:
- _rw_commit feeds the log-parsed full history (fallback to backend.history).
- commit derives the delta start from len(rebuild_history(parent)) /
  len(rebuild_hist_info(parent)) instead of the stored hist_len, so a poisoned
  count can't drop turns and a previously-lost turn self-heals on the next commit
  (the log is append-only, always a superset of the tree).

* chore(worldline): mark in-memory _do_rewind as the non-persistent degraded fallback

It chops the compressed live history (can't reach front-trimmed turns, keeps
truncated remnants, restores neither files nor working memory). Only used when
there is no checkpoint tree; the durable tree-rebuild path is always preferred.

* fix(worldline): derive tree working memory from the log, not live handler state

/continue resets agent.history (handler.history_info) to empty. _rw_commit
previously fed that live list as hist_info, so after a continue the per-turn WM
delta misaligned with the tree's log-derived WM and new turns' summaries were
dropped. commit now derives hist_info/key_info from the history it stores (the
full log) when not given, matching reconcile; _rw_commit stops passing the live
list. Tree WM is uniformly log-derived and survives the continue reset.

* feat(worldline): restore working memory on /continue (TUI-only, derived from the log)

continue_cmd clears handler.history_info on restore; the TUI's continue path now
derives history_info from the loaded log (same _derive_hist_info as the tree) and
writes it back to agent.history, so a continued session keeps its working memory,
consistent with the tree and live sessions. Scoped to tuiapp_v2 only — shared
continue_cmd is untouched, so telegram/discord/streamlit frontends are unaffected.

* refactor(continue): restore working memory on /continue via opt-in restore_wm

Move the WM restore from the TUI into continue_cmd as an opt-in. _load_history_into
derives history_info from the loaded log and writes it back to agent.history when
restore_wm=True; continue_inplace/continue_copy thread the flag and the worldline
TUI passes True. Default False keeps every other frontend (telegram/discord/
streamlit/shared chat) byte-for-byte unchanged. _derive_hist_info is self-contained
(no worldline dependency), same extraction口径 as the tree.

* perf(worldline): only re-parse the log in _rw_commit when front-trim is detected

_rw_commit re-parsed the whole log every segment to feed commit a full history;
for very long sessions (multi-MB logs) that adds a multi-second lag per turn. Now
it uses the fast in-memory backend.history by default and only falls back to
parsing the log when front-trim is detected — RewindStore.first_question() vs the
live history's first question (front-trim pops the first question, so they diverge).
Common case (no trim) pays nothing; correctness under trim is preserved.

* feat(worldline): conv/code bridge nodes + align _rw_commit to native log

- worldline: commit_bridge() + restore_plan() three-way (both/conv/code) with a new rw_tag field. conv bridges fork at parent(target); code bridges mount at parent(old_head) as a sibling of the current conversation node (same conversation, older code).

- tuiapp_v2: _rw_commit now reads the native log (parse_native_log) instead of the compressible live backend.history; stat-cached _rw_log_history; title from the real log delta; skip commit when there is no new complete pair. Cursor points at the bridge for conv/code; rw_tag rendered after the title.

- continue_cmd: add parse_native_log() public wrapper (complete Prompt->Response pairs only; [] for native-but-empty, None for non-native).

* fix(worldline): realpath 去重 key + 节点行数增删 + 剥离 project-mode

- key()/cwd 改用 realpath 解析 junction/symlink,同一物理文件只产生一个 tracked
  key(修 workspace 下 @提及绝对路径与相对写入产生双 key、回退误覆写当前内容)
- 新增 node_line_delta:按 node_diff 计每节点相对父节点的 +新增/-删除 行数,
  供 /rewind、worldline 显示代码变动量
- 重建历史时剥离 project-mode 注入块与自动注入标记(worldline._msg_user_text +
  continue_cmd._derive_hist_info),标题/提问只留用户原话

* feat(worldline/rewind): 面板与 rewind UI 精简重设计

worldline 面板:
- 右栏改用原生 OptionList(整项高亮/滑窗跟踪/点击映射,取代手写 ClickableList)
- 左右栏比例 3:2;详情面板精简(删掉与状态条/diff 重复的操作提示、时间、回退说明)
- 状态条重写为完整动宾短语,Enter 随聚焦切文案;右栏聚焦高亮改用更亮的 alt_bg
  (对齐左树,修此前聚焦态反而更淡的问题)

/rewind:
- 三列:用户 prompt · 上次时间 · 代码 +新增/-删除(绿/红,无改动显示「(无改动)」);
  倒序、聚焦底部、超长 prompt 省略号截断
- 延迟折叠(defer_collapse):选中先弹模式窗,确认才回退并清卡片;Esc 取消保留列表、
  焦点回到列表,不再留误导性「✓ 已选中」

其他:
- Ctrl+D 关会话时释放日志锁(abort + release_current),之后可原地 /continue

* fix(worldline): 回填输入框的 prefill 剥离 project-mode 注入

restore_plan 的 prefill/_prompt_of 走未清洗的 user_msg_text(树里的 user 消息取自
含注入的 native 日志),把 --- [PROJECT MODE:...] --- 一起塞进输入框。统一过
_strip_project_mode(幂等)。回归:temp/test_rewind_prefill_no_projectmode.py 9/9。

* refactor(tui): 删除被取代的旧 rewind 面板与死代码

- 删旧 /rewind 整簇:RewindScreen 类 + _on_rewind_pick + _rw_* 9 个 helper
  (已被内联 choice 卡 + RestoreModeScreen / RewindTreeScreen 取代,无 live 入口)
- 删未用 import next_same_depth/CheckpointTree、只写不读的 _diff_for/assistant_len
- 净 -276 行;import tuiapp_v2 通过、worldline 回归全绿

* fix(worldline): apply_code 回退失败不再静默,回传错误由 UI 提示

apply_code 直接写用户工作区文件,中途失败(权限/磁盘)会留下半回退状态。原先
restore_plan 吞成 changed=[],UI 显示「无变更」,用户毫不知情——全 PR 里失败半径
最大却唯一被静默的点。改为 _apply_code_safe 回传 (changed, code_error),
_rw_restore_node 据此追加「⚠️ 代码回退未完成…请检查」告警。
2026-07-07 08:36:28 +08:00
dd3xp 8325595ad7 merge main into RoundSquisheen 2026-07-06 11:14:32 -04:00
dd3xp c727ca34ca fix(desktop): refine chat ui and persistence 2026-07-06 10:53:40 -04:00
yiqi-017 a5c184c232 Merge branch 'yiqi_sessions_perf' into main
Fix desktop session-store scaling: store each session as its own
temp/desktop_sessions/<id>.json instead of one monolithic
desktop_sessions.json rewritten on every message. Write cost is now
O(one session) regardless of session count. Auto-migrates the legacy
file on first load; import reads both formats.
2026-07-06 14:35:26 +08:00
yiqi-017 bdd5309607 perf(desktop): store sessions one file each, not one monolithic JSON
Every message called _persist(), which rewrote the ENTIRE
desktop_sessions.json (all sessions, full messages + llm_history) under
the lock. Write cost was O(all sessions), so performance degraded badly
as sessions piled up.

Now each session is its own temp/desktop_sessions/<id>.json:
- _persist_session(s): atomic per-session write, O(one session)
- _delete_session_file(sid): remove on delete
- add_message / create / plan-bind / set_model / patch now write only
  the touched session; write cost no longer scales with session count
- _load_sessions reads the dir; one-time migration from the legacy
  monolithic file, which is then renamed to .json.migrated
- import_sessions reads both source formats (per-file dir + legacy),
  persists only newly added sessions
2026-07-06 14:05:31 +08:00
yiqi-017 157f4fec77 Merge branch 'yiqi_install' into main
Add "connect to a separate GenericAgent source" (thin-shell / design A):
a Settings option that points the packaged desktop app at a standalone
本体 checkout, so its bridge, agent code, memory and sessions all come
from that source. Invalid/missing override safely falls back to the
bundled runtime.
2026-07-06 02:54:17 +08:00
yiqi-017 300fe4ae34 feat(desktop): connect to a separate GA source (thin-shell / design A)
Adds a "GA source directory" setting so the packaged desktop app can run
against a standalone GenericAgent checkout instead of its own bundled
runtime/app — memory, sessions, model_responses and the agent code all
come from that 本体, live-shared with other frontends.

- lib.rs: ga_source_override settings key honored in get_or_discover_config
  BEFORE the bundle default; validated (agentmain.py + desktop_bridge.py),
  invalid/missing override falls back to the bundle (本体-moved safety net)
- set_ga_source / clear_ga_source / get_ga_source commands: write setting,
  stop current bridge, respawn from resolved config, reload webview
- startup uses the override-aware config for takeover + spawn
- ACL grants for the three new commands
- Settings > Features UI: pick source dir, show current, clear; zh/en i18n
2026-07-06 02:20:48 +08:00