Skip to content

Enhance FlowChat with export options, session management, and performance optimizations - #206

Merged
SWangHash merged 494 commits into
mainfrom
wc/rebase
Aug 10, 2026
Merged

SWangHash merged 494 commits into
mainfrom
wc/rebase

Conversation

@SWangHash

Copy link
Copy Markdown
Owner

/## Summary

Fixes #

Type and Areas

Type:

Areas:

Motivation / Impact

Verification

Reviewer Notes

Checklist

  • This PR is focused and does not include secrets, temporary prompts, generated scratch files, or unrelated artifacts.
  • Relevant verification is recorded above, or skipped checks are explained.
  • User-facing strings, docs, and locales are updated where applicable.

bobleer and others added 30 commits August 2, 2026 15:14
…continue subcommand

/compact and /usage now work for dispatch sessions end to end:

- Follow-up turns carry a kind (prompt | compact). A compact turn runs
  manual context compaction bound to the worker's own turn id, so its
  DialogTurn/ContextCompression events flow through the existing event
  loop, project into the transcript, and settle the job like any turn.
  New compatibility facade start_manual_compaction exposes the
  coordinator's caller-identified compaction without awaiting completion.
- New read-only 'query' verb answers persisted-state questions (usage
  report) from PersistenceManager in a short-lived process — no runtime
  bootstrap, no workspace runtime ownership, safe next to a running
  worker. Wired through SSH, device RPC, desktop dispatch_query command,
  and all peer-deny/workspace-policy/contract lists.
- Fixes a latent bug: the CLI had no 'dispatch continue' subcommand, so
  SSH targets and desktop-as-target hosts could not receive follow-up
  turns at all (only the CLI-daemon in-process path worked). 'continue'
  and 'query' are now registered clap verbs.
- Composer capabilities gain a per-command ops set: dispatch sessions
  execute /compact and /usage (driver-routed via FlowChatManager facades),
  the usage toolbar entry is visible again, and the remaining local-only
  commands stay hidden with the pickers.
- New session_query capability required alongside per_turn_options.
Images now reach dispatch sessions. Submit and continue carry inline
data-URL attachments which the worker converts to runtime image
attachments on the dialog turn; the optimistic projection turn renders
the same previews as a local send, and the target's DialogTurnStarted
metadata replays them after reconnect.

Transport budgets are explicit rather than silently truncated: SSH stages
the request file over SFTP (16 MiB total, 8 MiB per image, stdin cap
raised to 24 MiB), while the account-device envelope enforces a 192 KiB
inline budget with a clear use-an-SSH-target error. Steering has no
attachment channel, so images sent while a turn runs are refused with a
wait-for-this-turn message instead of the old blanket unsupported error.
New inline_attachments capability required at preflight.
The worker's event filter becomes a JobEventScope: SubagentSessionLinked
events whose parent is the job session (or an already-admitted child,
recursively) register the child and are published, all further events of
admitted children flow into the log, and child permission requests route
through the same durable mailbox. Parent turn discipline is unchanged and
foreign links are still refused (pinned by test).

On the controller, the observer stops suppressing the link event and the
driver resolver gains a fourth signal: a session whose parent chain leads
to a dispatch projection is itself dispatch-driven — never persisted
locally, never treated as a local backend session — with the session
lookup injected by FlowChatManager to keep the resolver a leaf module.
Child transcripts now render under dispatch projections exactly like
local subagent runs.
…ly executable commands

Self-audit of the refactor found four surfaces that would have grown into
exactly the maintenance burden this work exists to prevent:

- The protocol version lived in 4 copies (CLI u32, controller u64, SSH
  transport u64, Web UI) and the capability list in 3 authoritative copies
  plus a weaker partial inside validate_dispatch_protocol whose submission
  path silently lacked the v4 entries. All Rust copies now derive from one
  services-core dispatch_contract module (version, capability names,
  attachment shape, structural limits, shared validator); the submission
  gate is now the full surface narrowed to the selected approval policy,
  strictly stronger than before.
- The controller duplicated the target's semantic whitelists (query kind,
  turn kind/prompt rules). Those are the target's contract; a stale
  controller copy would reject valid requests after a target upgrade. The
  controller now enforces only transport-owned checks (sizes, budgets,
  idempotency-id format) plus the pre-baseline approval-policy fail-fast.
- The Web UI's contract test now reads the shared Rust contract file and
  pins version + capability names cross-language, and dialog fixtures
  spread BASE_DISPATCH_CAPABILITIES instead of hand-copied lists — a
  capability bump is one Rust edit, one frontend edit, and CI fails on any
  drift. The SSH protocol tests (feature-gated, previously not exercised in
  this branch's runs) now derive their fixtures from the same single list.
- The slash-command picker now offers exactly the ops the session can
  execute. Previously (predating this refactor) a dispatch user could pick
  /goal from the list and have it sent to the remote agent as literal
  prompt text.
Move runtime capabilities from the workspace root to their consuming crates and feature owners. Keep bitfun-core no-default builds viable with fail-closed cleanup and metadata-backed dependency guardrails.
- Keep transient turn pins pending until geometry is stable.
- Expand temporary Virtuoso materialization range during navigation.
- Preserve logical pin ownership while target elements are rematerialized.
- Gate initial positioning to the first Virtuoso mount.
- Add regression coverage and document the scroll-stability contract.
- Reserve a stable scrollbar gutter on the projection handoff overlay.
- Add a regression test for overlay and Virtuoso width alignment.
- Verify focused FlowChat styles and Web UI type checking.
- add explicit exact and best-effort turn pin alignment policies
- avoid synthetic footer space when turn navigation reaches the natural scroll limit
- keep sticky-latest alignment exact for streaming output
- update navigation tests and scroll stability documentation
…etup

Compiling BitFun on someone else's machine is not something a dispatch
controller should be able to do. It needed a Rust toolchain, a C compiler,
git, ~6 GB of scratch space, and tens of minutes on a host the user only
meant to run one task on — and it existed solely to paper over targets no
published binary fits. Those targets are now reported as unusable instead.

The removal is end to end, so the capability cannot come back through an
unused door: the `dispatch_install_cli_source_start` command, its Tauri
adapter, the Server Host route, the Desktop controller-source archiver,
both remote build script generators, `source_build_availability`, and the
probe's cargo/git/cc/free-space detection are all gone. The probe now
fills `install_error` in the two branches that previously returned nothing
and leaned on the source-build card, so a target with no compatible
release explains itself rather than failing later at submit. A contract
test pins that no routing table or client API mentions the command.

The dialog loses the source build and, with it, the install poll/cancel
and console machinery — nothing in this dialog starts an install anymore;
submit does. What remains is a form that was four box levels deep for one
path: a modal, a section card with a filled header bar, an inner card, and
a `code` pill. It is now one flat stack separated by hairlines, with a
border reserved for the two things that are actually interactive (the
revision input and the approval options). The automatic-setup and
model-sync panels fold into the target check they belong to, so five
sections become three and the whole form fits without scrolling.
…ed model

Picking a model in the composer appeared to do nothing on the first switch
after client startup; a second click on the same model made it stick.

The first explicit model update for a session is what pulls that session off
disk. If its persisted model is no longer configured, restore repoints it to
"auto" and broadcasts SessionModelAutoMigrated. That notice therefore lands
*after* the composer already wrote the newly picked model optimistically, and
the handler applied it unconditionally, reverting the selection. The second
click found the session already in memory, so no restore, no notice, no revert.

The backend itself switched correctly; only the store was rolled back. That is
not cosmetic: syncSessionModelSelection pushes the store value before every
send, so an unnoticed revert would overwrite the correct backend model with
"auto" on the next turn.

Apply the notice as a compare-and-swap instead: migrate only while the session
still holds the model the backend migrated away from (or holds no selection).
The CLI already guards this way in modes/chat/selection.rs; the desktop UI was
the only consumer applying these events blindly. Background restores that
genuinely need the migration still match and still apply.

Also stop the selector from reporting a failed switch as a successful one: roll
back the optimistic write and surface an error toast when the update rejects.
Split lightweight service and SSH facade features from full product composition, remove redundant Core dependency ownership, and guard the recursive feature closure with boundary tests.
Gate Core LSP, terminal, workspace, watcher, and remote services behind additive feature profiles. Move stable workspace identity helpers into services-core, isolate libgit2-backed session support, and enforce the closed profiles with boundary checks and focused fail-closed coverage.
- propagate scene activity into the virtual message list
- rebase scroll geometry and reservations when the viewport becomes visible
- defer pinning and stream-end reconciliation while the scene is inactive
- add regression coverage for hidden viewport transitions
- include the viewport coordinator dependency where it is used
- remove the unused dependency from collapse reservation handling
feat(flow-chat): add windowed history loading and stable turn navigation
Gate filesystem, storage, process, and instruction owners behind additive features. Keep Tokio and platform capabilities owner-scoped and protect the narrow profiles with boundary contracts.
Keep rich unsent drafts scoped to inactive TUI sessions and add OpenCode-compatible prompt stash palette actions. Add bounded opt-in terminal attention for completed turns and input requests.
- expose persisted session lineage through desktop and remote session APIs
- merge lineage snapshots with live state in a recursive Flow Chat tree
- add localized tree controls, lifecycle states, and focused coverage
- Add recursive Agents session lineage tree with live status tracking.
- Replace the background activity panel with a background command panel.
- Support non-cascading cancellation for individual agent sessions.
- Highlight the Agents entry for active foreground and background descendants.
- Preserve persisted session titles and manual tree collapse state.
- Update desktop/server APIs, localization, styles, and focused tests.
zvzuola and others added 15 commits August 7, 2026 19:45
…eset editor

Replace hand-written provider/model inputs in the reasoning preset editor with
cascading dropdowns backed by the merged provider catalog. Selecting a provider
filters models to those that support reasoning, and an empty selection is valid
for models that are not yet adapted.

Add tests covering provider aggregation, reasoning-capable model filtering,
cascading filter, unknown-provider handling, and value echo.
- use the full models.dev snapshot for reasoning provider/model bindings
- expose catalog source, revision, cache path, timestamp, and model counts
- add manual refresh, cache directory reveal, and offline update guidance
- refresh the UI when the catalog changes
- add Rust, remote transport, and frontend coverage
将外部 AI 应用设置收敛为默认页少量控制:应用行改为可展开树,仅保留总开关、已启用能力图标与单一待确认入口;打开应用开关即应用推荐设置,关闭撤下运行能力,custom 模式重新启用时保留原有覆盖;全局关闭时应用开关保持失效。移除独立 Hooks 一级入口,旧 hooks 深链归一到外部应用设置并复用同一面板;清理 connect 对话框相关死代码与失效 i18n 键。行为由应用模型与设置页测试冻结并逐项审查。
The permission mode behind the chat input control was stored as two global
config knobs (policy preset + auto-approve preference), so switching it in
one conversation moved every other open session. Users who keep a read-only
exploration session next to an editing session had no way to hold different
modes at once.

Make the mode a first-class value resolved per submission as
`turn -> session -> project -> global default`:

- Add `PermissionMode` (ask / auto_approve / full_access) to product-domains,
  with the preset and auto-approve knobs derived from that single value so a
  round can no longer run with a preset from one mode and an approval
  behavior from another. The project layer is reserved, not yet written.
- Persist the session's own selection on `SessionConfig.permission_mode`.
  `None` keeps following the user-level default, so existing sessions behave
  exactly as before and still track later changes to that default.
- Resolve the mode once per submission in the coordinator and read it from a
  single context key downstream. The legacy `auto_approve_ask` metadata key
  is still honored for CLI, dispatch, and persisted submissions.
- Demote the settings-page value to the default for sessions that have not
  chosen their own mode, and surface the session override in the chat input
  with a scope label, an indicator, and a reset action.
- Add an opt-in "next message only" mode that rides on the submission and is
  never persisted.

Also fixes two subagent inheritance gaps found while wiring this up: the
Task tool forwarded only boolean invocation facts, and the external subagent
delegation path read submission metadata without resolving the session
layer. Both dropped a delegated child back to the global default. The parent
runtime ceiling still bounds the child, and a `full_access` mode remains
bounded by project, agent, enforced, and constraint layers.
Make review decisions direct and authoritative across GUI and TUI, clarify disclosure and empty states, and avoid unnecessary snapshot projection work.
chore(i18n): unify copy wording in zh-CN and zh-TW locale
@SWangHash
SWangHash force-pushed the wc/rebase branch 7 times, most recently from e01cd80 to 46a4da8 Compare August 10, 2026 09:15
@SWangHash
SWangHash merged commit ea9c18a into main Aug 10, 2026
1 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.