Commit Graph
254 Commits
Author SHA1 Message Date
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
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 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 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
yiqi-017 4798e72f3f fix(desktop): render sidebar after importing sessions
loadSessions() only refreshes the data model; the sidebar DOM is drawn by
renderSessionList(). Imported sessions therefore only appeared after the
next render (e.g. sending a message). Call renderSessionList() right after.
2026-07-06 01:13:29 +08:00
yiqi-017 aff6560440 feat(desktop): merge desktop_sessions.json on memory import
Import now also merges the source's temp/desktop_sessions.json into the
current session list (dedup by id), updating both memory and the on-disk
file so past desktop chats reappear in the sidebar immediately.

- manager.import_sessions(): id-dedup merge, in-memory + persist
- import handler returns sessionsAdded/sessionsSkipped
- frontend shows session count in toast and reloads the sidebar
2026-07-06 00:48:15 +08:00
yiqi-017 ec44d69bfe feat(desktop): clarify import-memory targets the GA root dir
- button label now says "select GenericAgent root"
- pick_directory accepts a title; native dialog shows the hint
- browser-fallback prompt clarifies root dir vs memory folder
2026-07-05 23:46:19 +08:00
yiqi-017 4cda8cadb7 fix(desktop): allow pick_directory command in ACL
The import-memory button failed with "Command pick_directory not allowed
by ACL" because Tauri v2 requires custom commands to be granted in the
capability. Add allow-pick-directory permission and grant it.
2026-07-05 22:55:10 +08:00
yiqi-017 74275f8980 feat(desktop): add import-memory feature in settings
Lets users import memory/ and temp/model_responses/ from an existing
GenericAgent install into the desktop app's ga_root, so past sessions
and memory are not lost when running the standalone desktop bundle.

- bridge: POST /memory/import copies memory (backup-then-overwrite) and
  model_responses (fill-missing), returns counts + backup dir
- tauri: pick_directory command (rfd native folder picker)
- frontend: "Import memory" button in Settings > Features + zh/en i18n
2026-07-05 22:28:17 +08:00
dd3xp 4d4c220152 Clarify desktop plan collapse labels 2026-07-05 05:43:37 -04:00
dd3xp 158aeabfa4 Align desktop plan mode activation with TUI 2026-07-05 05:14:52 -04:00
dd3xp 54e8d46603 Fix desktop session rename editing 2026-07-04 22:35:22 -04:00
dd3xp d205cd023e merge: bring test desktop packaging and model fixes into main 2026-07-02 18:40:02 +08:00
yanghang c471036839 refactor(desktop): move desktop_release/ → frontends/desktop/packaging/
Co-locate desktop packaging scripts with the Tauri app, declutter repo
root. Drop legacy manual-install flow (install.bat/start_windows.bat/
README_WINDOWS.md) and unused apps/ placeholder tree. Update CI workflow
paths and TODO references accordingly.
2026-06-26 20:12:46 +08:00
yanghang c0e90263c4 fix(desktop): conductor reloads mykey per-task even with no bound model
_apply_desktop_model is called before every conductor task to make the agent
reflect the current desktop config. But the mykey reload only happened as a
side effect of next_llm(), which was gated on a bound model index (no != None).
On a fresh install nothing is selected (conductor.llmNo and ui.llmNo both null),
so no == None, next_llm was never called, and a conductor that started on the
empty template never picked up imported keys — the next message crashed on the
stale empty mixin ('dict' object has no attribute 'backend').

Add the no-bound-model branch: call agent.load_llm_sessions() (mtime-guarded,
rebuilds only when mykey actually changed) so a live conductor reflects imported
keys on its next task without any restart or task interruption.
2026-06-26 17:24:14 +08:00
yanghang 1e6f370cfd fix(desktop): restart conductor/scheduler only when actually broken after mykey import
conductor and scheduler are separate subprocesses that read mykey once at
startup. After a mykey rewrite (import keys / edit channel config), a healthy
running conductor already hot-reloads mykey on its next task via its own mtime
check, so it needs no restart — restarting it would only interrupt an in-flight
task.

So restart an extra only when it is genuinely broken: the process exited
unexpectedly (covers scheduler dying on a bad config), or the process is alive
but its "Exception in thread conductor-agent" crash signature is in the captured
log (uvicorn still up but the agent thread is dead and can no longer process
tasks). A fresh log buffer per start means the signature only reflects the
current process. Bridge-only; conductor core and agentmain untouched.
2026-06-26 16:18:21 +08:00
yanghang 352525f87d fix(desktop): refresh conductor model chip on profile-only reloads
loadModelProfiles only updated the main model chip, never
state.conductorModelName. The mykey-import path (and add/remove-mixin,
reorder, add/delete model) call loadModelProfiles without
loadBridgeConfig, so after importing keys the conductor chip stayed on
its stale label (e.g. the empty "渠道组(自动故障转移)") until a manual
model switch recomputed it. Recompute conductorModelName from the fresh
profiles when a conductor model is bound.
2026-06-26 14:37:15 +08:00
yanghang 1c3c14a5f8 fix(desktop): bind conductor model to its own session 2026-06-24 22:23:25 +08:00
yiqi-017 5e7e5f608e refactor(desktop): model switching only via /session/{sid}/model
Remove the implicit model-write that rode along with each prompt. The
frontend no longer sends llmNo on session/prompt, and the bridge no longer
reads/forwards it there — sending a message now uses only the session's
bound sess.llm_no (falling back to the global default). Model switching
goes through the single POST /session/{sid}/model entry point.

selectModel now rolls back the chip + shows a toast when the switch request
fails, so the frontend display never diverges from the backend.
2026-06-24 18:29:13 +08:00
yiqi-017 e0117c40de feat(desktop): per-session model binding with backend as source of truth
Session.llm_no is now the authoritative per-session model selection
(persisted to desktop_sessions.json). Frontend state.llmNo becomes a
display cache; switching a session re-displays its bound model, and the
chip follows the backend's live model for native models too (not just
mixin failover).

- bridge: Session.llm_no field + persistence; submit_prompt/run_agent_turn
  read sess.llm_no with global ui.llmNo as fallback; make_agent/restore
  seed from it; new POST /session/{sid}/model; _live_model reports llmNo
- app.js: applyLiveModel supports native; setActiveSession re-displays
  bound model; selectModel posts to session route + updates global default;
  remove ga_llm_no localStorage
- conductor unchanged: keeps reading global default ui.llmNo
2026-06-24 16:44:58 +08:00
dd3xp 788c534762 restore: bring back lsdefine's 70792af fix lost in -X theirs merge
The prior merge resolved conflicts to the desktop/main (graft) side,
which silently reverted lsdefine's recent upstream fix (inMixin check,
ask_user schema, turn-25 prompt). Restore the 4 files to origin/main.
2026-06-24 11:23:46 +08:00
dd3xp b13ff03380 chore: sync conductor.py to upstream lsdefine/GenericAgent @ c85b59e
3-way merge (base=b365945, ours=lsdefine, theirs=desktop fork) finished
with 0 conflicts: lsdefine's prompt rewrites + int(time.time())
regression land cleanly; desktop fork's 6 patches (CORSMiddleware,
_desktop_llm_no, cost_tracker.install, /token-stats, add_chat
files+images, --no-browser) are preserved on top.
2026-06-23 01:17:31 +08:00
dd3xp eaffd01e6c chore: sync framework to upstream lsdefine/GenericAgent @ c85b59e (excluding conductor.py + frontends/desktop/) 2026-06-23 00:16:37 +08:00
yanghang de00ede0cf feat(desktop): merge tested desktop updates without release packaging 2026-06-22 19:06:11 +08:00
yanghang a1e44957e4 feat(desktop): standard macOS DMG and themed confirm dialogs 2026-06-22 17:23:33 +08:00
yanghang a258c75bcc fix(desktop): replace native dialogs and add mac dmg artifact 2026-06-22 16:35:44 +08:00
yiqi-017 9103f8e8c8 style(desktop): drop the accent left bar on selected model dropdown item
Selected item in the model dropdown now uses only a tinted background + bold
(both light and dark); the inset left bar is removed per design preference.
2026-06-22 15:37:25 +08:00
yiqi-017 f0f2b50763 style(desktop): send button colors + clearer selected model in dropdown
- Send button: light mode now black (was green), dark mode bright blue
  (#2559d8 / hover #3a6ef0).
- Model dropdown selected item is now obvious: light mode gets an accent
  left bar + tinted bg + bold; dark mode gets a tinted bg + soft-white left
  bar + bold.
2026-06-22 15:24:14 +08:00
yanghang 0f5f99f928 fix(desktop): 用 build-id 判别 bridge 归属 + 强制接管,杜绝连到旧 bridge
- build.rs 注入 GA_BUILD_ID(commit 短哈希+构建戳),每次构建必不同,
  即使 tauri.conf 版本号不变也能区分(原 identity 只比 ga_root 路径,
  原地升级/同版本重发时旧 bridge 被误判'匹配'而不接管)
- bridge /services/identity 增报 build_id;tauri 经 sanitize_bundle_env 用
  GA_BUILD_ID 环境变量给所spawn 的 bridge 打标
- bridge_identity_matches: build_id 不一致(或缺失/旧 bridge)即判不匹配 → 接管
- takeover_stale_bridge: POST /exit 后端口仍占(旧 bridge 无该端点),
  force_free_bridge_port() 按端口强杀监听进程(Win netstat+taskkill / Unix lsof+kill)
- 本机 cargo check 通过
2026-06-22 03:11:19 +08:00
yanghang 9353116bc0 fix(desktop): Linux 快捷方式带图标 — .desktop Icon 指向包内 GenericAgent.png
- lib.rs: Linux ensure_desktop_shortcut 的 Icon= 改为包内 GenericAgent.png
  (Icon 需真实图片文件,原来指 AppImage 路径不显示图标),缺失时回退
  主题图标 application-x-executable
- CI: 将 src-tauri/icons/icon.png 作为 GenericAgent.png 打进 Linux 包顶层
2026-06-22 02:34:18 +08:00
yanghang eff7c83b8b feat(desktop): Linux/mac 桌面快捷方式 + 便携卸载器(对齐 Windows)
- lib.rs: ensure_desktop_shortcut 增加 Linux(写 .desktop 到 ~/Desktop 与
  ~/.local/share/applications)与 macOS(Desktop 软链 .app)实现;
  shortcut_should_ask/decide/maybe_setup_shortcut 放开到非 Windows
- 新增 desktop_release/scripts/linux/uninstall.sh 与 macos/uninstall.command:
  停 bundle 自有进程 → 删本 bundle 的快捷方式 → 删设置 → 清 WebKit/WKWebView
  数据 → 删 bundle 目录(作用域限定本 bundle,不动其他安装)
- CI: 将卸载脚本打入 Linux/mac 便携包顶层
- 已在 Ubuntu 24.04 真机验证: cargo build 通过、uninstall.sh 隔离测试通过
2026-06-22 02:00:14 +08:00
yanghang 9e7f8dc70a Merge origin/test_fast into test: Windows 快捷方式/卸载器/窗口最大化 2026-06-22 01:27:45 +08:00
yanghang 71828c9103 feat(desktop): 渠道组(自动故障转移)模型管理 + 流式开关 + 运行态模型显示
- 模型管理分为「渠道组(自动故障转移)」与独立模型两层:渠道组可展开、
  拖拽调整成员优先级,独立模型用 ➕ 加入(已在渠道组则提示)
- 后端 list/add/remove/reorder mixin 成员均走 mykey 结构解析与校验
  (Native 一致性、reorder 仅重排同组、删除级联清理 llm_nos)
- 默认配置:空渠道组 + 无独立模型(新装不再出现不可用模板模型)
- 添加/编辑模型表单新增「响应方式」流式开关;编辑保留高级字段
- chip/菜单显示渠道组当前实际模型(随故障转移更新),修复语言切换滞后
- 字体/选中态统一(sans 标题、等宽补中文兜底、选中不变淡)
- llmcore: MixinSession 增加 current_name 暴露当前子会话名
2026-06-22 01:24:53 +08:00
yiqi-017 cf17adab24 feat(desktop): maximize main window + uninstall clears WebView2 data
- Main window now opens maximized (maximized: true); 1280x800 stays as the
  restore size. Previously it always opened windowed.
- Uninstaller now also removes %LOCALAPPDATA%\com.genericagent.app (WebView2
  EBWebView cache + localStorage), which lives outside the bundle. Only the
  Tauri desktop shell uses it, so removal is safe.
2026-06-22 00:50:42 +08:00
yiqi-017 24c6a64d0e Revert no-cache middleware for bridge static assets
Back out the no_cache_middleware added in f3a85d1. Fresh installs have no
cache so it is not needed for first run; cache during testing is cleared
manually. The uninstaller arg-bug fix from the same commit is kept.
2026-06-22 00:38:08 +08:00
yiqi-017 cd9f029edc fix(desktop): uninstaller arg bug + no-cache for bridge static assets
Bug 1 (uninstall.bat could not delete the folder): %~dp0 ends with a
backslash, so -BundleDir "%~dp0" passed "...\dir\" — the trailing \" escaped
the closing quote and PowerShell received a path with a literal quote
("Illegal characters in path"). Resolve-Path failed, the deleter ran rd on a
garbage path, and nothing was removed. Strip the trailing backslash in the
.bat before passing, and defensively trim stray quotes/separators in the ps1.

Bug 2 root cause (shortcut prompt / UI showed stale code after updates):
the bridge served app.js via aiohttp's static handler with only
ETag/Last-Modified and no Cache-Control, so WebView2 heuristically cached it
and kept serving an old app.js after rebuilds. Add a no_cache_middleware
that sets Cache-Control: no-cache, no-store, must-revalidate on GET/HEAD.
2026-06-22 00:31:11 +08:00
yiqi-017 eab0b4a02b chore(desktop): remove temp diagnostic banner from shortcut prompt
Bug 2 root cause was WebView2 serving a stale cached app.js (no
Cache-Control header on the bridge static response). With a fresh
extract / cleared cache the first-run prompt works. Revert the diagnostic
instrumentation back to the clean maybeAskDesktopShortcut.
2026-06-22 00:08:26 +08:00
yiqi-017 0191b28609 chore(desktop): TEMP diagnostic banner for first-run shortcut prompt
Not a fix — instruments maybeAskDesktopShortcut with an on-page banner
reporting __TAURI__ availability, shortcut_should_ask result, and whether
window.confirm fires/returns, so we can locate why the first-run prompt
never shows. To be reverted once the cause is confirmed.
2026-06-21 23:41:33 +08:00
yiqi-017 4e1fa78ecf fix(desktop): first-run shortcut prompt + uninstaller folder deletion
Bug 1 (shortcut prompt only showed on the second launch): a native rfd
dialog spawned from the Rust startup thread has no parent window and got
buried behind the main window on first launch. Move the prompt to the web
UI: add shortcut_should_ask / shortcut_decide commands; the frontend asks
once via window.confirm after load (always on top). The startup thread now
only self-heals the shortcut path when already enabled.

Bug 2 (uninstall.bat could not delete the folder): kill ANY process whose
exe lives inside the bundle (not just GenericAgent/python by name), and run
the folder delete from a detached temp .bat that retries the recursive
remove ~20x to cover the window where uninstall.bat releases its handle.
2026-06-21 23:18:29 +08:00
yiqi-017 ccd912da08 feat(desktop): auto-create desktop shortcut on first run (Windows)
Windows portable bundle now offers to create a desktop shortcut on first
launch via a native yes/no dialog, remembers the choice in
~/.ga_desktop_settings.json (desktop_shortcut), and self-heals the .lnk
target to current_exe() on every enabled launch so a relocated bundle
keeps working.

Also add read_settings/merge_settings and route the three existing
settings writers through merge, so sibling keys (like desktop_shortcut)
are no longer clobbered by the python_path/project_dir rewrite.
2026-06-21 21:48:24 +08:00
lyx 3e1b516f0f fix(desktop): expose tauriInvoke for model config export
exportMykeyToDir runs outside the bridge IIFE; call via window.ga.tauriInvoke.
2026-06-19 23:47:08 +08:00
lyx d61820e539 fix(desktop): export model config in WebView2 exe
Bump app.js cache bust; use Tauri save dialog in exe; rename import/export
toasts to 模型配置已导入/已导出.
2026-06-19 23:36:26 +08:00
lyx f1eab86ac6 feat(desktop): export model config from settings (frontend-only)
Add export button that writes mykey.py via directory picker or download;
rename import label to clarify it imports model config (mykey.py).
2026-06-19 23:06:28 +08:00
lyx 11dc64a7c2 fix(desktop): invalidate mykey cache on import save
Import mykey via POST /services/mykey now uses _save_mykey_text so stale
LLM profiles are dropped from the model list after replacing mykey.py.
2026-06-19 22:55:59 +08:00
lyx d4560ea7bf feat(desktop): settings features, bridge panel fixes, align startup with test
Add settings "Features" section with mykey import and service manager entry.
Split spawnBridge (panel) from test-style startBridge boot; fix bridge-exit
UI race; restore takeover_stale_bridge on launch; allow Tauri IPC for
start_bridge from remote bridge UI.
2026-06-19 22:37:24 +08:00
LLYYXX 333476c4e5 1. 设置页模型配置下面新增“后台服务管理”按钮,点击后关闭设置弹窗并跳到 后台服务 -> 状态面板
2. 状态面板里 Bridge / Conductor / Scheduler 支持启动和退出
2026-06-19 21:46:12 +08:00
yanghang 2a8716909a fix(desktop): keep backend persistent on window close (Model A) — don't stop conductor/scheduler so IM bots/tasks survive 2026-06-19 05:48:55 +08:00
yanghang b4c66bff6b fix(desktop): drop extras port-busy probes that self-detect the bridge's own auto-started conductor/scheduler 2026-06-19 05:33:57 +08:00
yanghang ea28559f8f fix(desktop): take over stale/foreign bridge on 14168 (identity handshake + shutdown), so a new version never loads the old install's UI 2026-06-19 05:00:44 +08:00