Repository navigation
fix(cli): reload config edits, add dispatch controller, dedupe bot device list - #3648
Merged
bobleer merged 5 commits intoOct 31, 2026
Merged
Conversation
The IM bot device menu added a synthetic local entry and then every online account device, including the host serving the bot, so that host appeared twice. Fold the relay entry whose id matches the local device identity into the local entry, and return a chat that had selected its own host as a remote device to the local target.
Long-running hosts (CLI daemon, desktop, server) kept the configuration loaded at startup until an in-process reload, so hand edits or another process's writes needed a restart. Track a fingerprint of the content the config manager last loaded or wrote and poll the file every 2 seconds; reload and broadcast only when another writer changed it. Invalid mid-edit content keeps the current configuration, a missing file is never recreated, and reloads do not signal local edits to account sync.
The CLI only implemented the target side of Detached Dispatch. Add `openbitfun dispatch outbound targets|submit|status|list|cancel`, a JSON controller over the Core dispatch owner for saved SSH connections and same-account devices, excluding this host. Move the account-device host_invoke envelope and agent-identity translation into Core (AccountRuntimeDeviceDispatchRpc) so Desktop and CLI share one implementation, and admit dispatch-store into the reviewed CLI Core closure.
Resolve the global config service on every poll instead of capturing the instance created at initialization, so a replaced service is not left stale.
Update the CLI reviewed Core feature fixture and replace the blanket dispatch-store exclusion test with one that allows the CLI controller and still rejects the feature for another reviewed closure.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three CLI host problems reported from a WeChat-driven daemon:
app.json; the CLI daemon kept serving the config it loaded at startup (e.g.ListModelsstayed stale after editing the model list). Core now polls the config file every 2 s and reloads when another writer changed it.openbitfun dispatch <verb>is the target-side protocol; there was no way to submit a job from the CLI. Addsopenbitfun dispatch outbound targets|submit|status|list|cancel.Type and Areas
Type: bug fix / feature
Areas: Rust core (config, dispatch, remote-connect bot), CLI, desktop/Tauri (dispatch adapter refactor), core boundary script, docs
Motivation / Impact
service/config):ConfigManagerrecords a fingerprint of the content it last loaded or wrote;ConfigService::reload_if_changed_on_diskreloads and broadcastsModelConfigurationUpdated+ConfigReloadedonly when another writer changed the file. Own writes do not trigger reloads; invalid mid-edit content keeps the current config (warned once per distinct error); a deleted file is not recreated; reloads do not firelocal_changes, so account sync does not echo them. The poller is started byGlobalConfigManager::initializeunderagent-runtime, so CLI daemon, desktop, and server all benefit. Polling rather than a file watch keeps atomic replacement and network home directories working.submit_device_dispatch,submit_dispatch, etc.).--targetaccepts a device name/alias,device:<id>, orssh:<connectionId>; the local device is excluded from targets; offline devices fail without local fallback;--approval-policyis required (autoorreject-and-report;remoteis not offered because the CLI has no answer command yet). The account-devicehost_invokeenvelope and agent-identity translation moved from the desktop adapter into Core (AccountRuntimeDeviceDispatchRpc,encode/decode_device_dispatch_*) so desktop and CLI share one implementation.dispatch-storeis admitted into the reviewed CLI Core closure; the boundary script keeps it forbidden for every other reviewed closure.DeviceIdentity::from_current_machine()is folded into the local entry (本地设备 (<host name>)); a chat that had selected its own host as a remote device is returned to the local target. Desktop and mobile web pickers already filtered the self device.Remote scenarios: remote control (IM bot device menu) and Detached Dispatch controller paths are covered by unit tests only. No live relay, WeChat, SSH, or second-device run. The dispatch wire protocol (v6) and the target verbs are unchanged.
Upgrade compatibility: no persisted shape changes. The config fingerprint is in-memory only.
Verification
cargo test -p openbitfun-core --lib --features agent-runtime,ssh-remote,remote-connect,dispatch-store,web-tools -- device_menu_ service::config device_dispatch_envelope(96 passed), including newreload_if_changed_on_disk_picks_up_external_edits_only,device_menu_folds_this_host_into_the_local_entry,device_dispatch_envelope_round_trips_success_and_errorscargo test -p openbitfun-cli --bin openbitfun -- dispatch_command_tests dispatch::outbound(3 passed)cargo test -p openbitfun-desktop --lib dispatch_api(2 passed)cargo check -p openbitfun-cli,cargo check -p openbitfun-desktop --testspnpm run check:core-boundaries,pnpm run check:repo-hygieneOPENBITFUN_USER_ROOT/OPENBITFUN_HOME: startedopenbitfun --verbose server, appended a model toapp.json; the log showed exactly oneConfiguration reloaded after an on-disk changeabout 2 s after the edit and no reloads before it.dispatch outbound targetsandlistprint[];submitto a device andstatusfor an unknown job print a JSONerrorand exit 1 without local fallback.Related-surface review: Desktop
DeviceStatusControl, the peer-device roster, mobile webDevicesPage/SessionListPage, and the CLI TUI account panel already filter or mark the self device, so the IM bot menu was the only duplicate. Restored bot state already drops remote device selections, so a stale self-selection cannot survive a restart. The poller resolves the global config service on each tick so a replaced service is never left stale.Checked refreshed upstream
mainand open PRs before implementation; none covered these issues.Reviewer Notes
dispatch-storeban for the CLI came from the build-speed closure isolation (0e64e80), not a semantic rule; its extra dependencies (base64,services-core/dispatch-workspace) were already in the CLI closure.Checklist