Skip to content

feat(bot-mode): complete Group Chat continuity, control, and files - #98307

Draft
dokterdok wants to merge 104 commits into
NousResearch:mainfrom
dokterdok:feat/bot-mode-group-chat-complete-20260830
Draft

feat(bot-mode): complete Group Chat continuity, control, and files#98307
dokterdok wants to merge 104 commits into
NousResearch:mainfrom
dokterdok:feat/bot-mode-group-chat-complete-20260830

Conversation

@dokterdok

@dokterdok dokterdok commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Keep Your Bots Working Together, Then Pick Up From Your Phone

This is the complete Group Chat field build for #97681. Bots on the same or different gateways can exchange messages and files while Desktop is closed, provided their gateways support and can reach the shared group. The owner can return in Desktop or use a connected messaging chat to inspect progress, steer the work, retrieve files, or Stop it.

Create a Group Chat normally. Hermes selects the available continuity path and shows when Desktop is still needed. Older gateways keep the compatible Desktop-driven behavior.

Current field gate: hosted Bot-to-Bot file handoff and human retrieval work in real-client tests, including file retrieval after an execution grant expires. Classic Desktop-driven file handoff also passes a real six-Bot writer/reviewer transfer and exact Desktop download. The missing classic messaging consumer and its recovery cases are now implemented and independently reviewed. The final packaged Desktop acceptance run is in progress.

A Concrete Workflow

  1. Create a group with a planning Bot, a developer, and a reviewer, even if they run on different gateways.
  2. Ask them to prepare a launch brief. A Bot can share the resulting Markdown file with another Bot, which receives the verified bytes rather than a machine-local reference.
  3. Leave Desktop. In your authorized Telegram or Signal conversation, use /group and choose the group to see recent work.
  4. Open Files to find the newest output, distinguish same-name revisions, search older files, and retrieve the selected version. Native menus are used where the client supports them.
  5. Send a follow-up, inspect participating Bots, answer an exact pending approval, or Stop the work. An uncertain send or unavailable gateway is reported explicitly.
Where shared files live, and which Bots receive them

In a hosted Group Chat, the home gateway retains a verified shared copy. A Bot receives bytes when its task includes the attachment; the other Bots do not automatically synchronize a copy to their disks. Files lists the available items and downloads only the one you choose.

flowchart TB
    W["Writer Bot"] -->|"Shares a file"| H["Group's home gateway: stored shared copy"]
    H -->|"Bytes for the admitted task"| R["Reviewer Bot"]
    H -->|"Selected download"| U["You: Desktop or messaging"]
    H -->|"Attachment reference"| L["Group history and Files list"]
Loading

These are roles, not necessarily separate machines: the home gateway may also run one or both Bots. Mentioning a reviewer directs the work, not privacy. Other eligible group members can receive the file on a later turn. This is neither a shared disk nor an automatic backup on every gateway.

Classic Desktop chats use a separate storage path. Their user uploads are retained by Desktop; explicitly shared Bot output is retained on the producing gateway, with verified references in Desktop. A packaged six-Bot writer/reviewer transfer and exact Desktop download have passed. The diagram above describes hosted chats only.

What Is In This Build

The build composes the Desktop continuity client, durable Files, Bot-to-Bot file handoff, native messaging controls, shared history, approvals, and route recovery. The source commits and contributor history remain preserved.

Recent repairs include named-profile upload/download routing, exact credential retirement, stale route fencing, stable file selection after new arrivals, Home changes surviving failed writes, simultaneous Stop redelivery, and retaining Bot output across publication recovery. Published repairs have owning source PRs; the newest classic-file candidate keeps backend and Desktop commits separately selectable while its source drafts are prepared.

This remains an integration draft, not a request to merge every layer as one change. #97846 is the Desktop-only client; #98072 owns Files; #99159 owns Bot-generated handoff; #98073 owns messaging controls and its optional Files consumer; #100016 owns route recovery. #99107 and #96162 remain independent. The maintainer's staged merge direction still applies.

The new Desktop Files client and classic Bot file-export backend are already available as focused drafts in the contributor fork, included in this field build. They preserve the upstream prerequisites' scope while their live acceptance checks finish. Please coordinate related implementation through #97681 and reuse the linked authored commits rather than rebuilding these paths independently.

Validation And Remaining Gate

Current integration head: 25cda8f8f76729de746dcaf424dfbf883323fb14. The final classic-command repairs pass 120 focused tests, all three TypeScript checks, changed-owner lint and the strict 2K check. One independent reviewer cleared the final code with no remaining confirmed P0/P1/P2/P3 in the reviewed boundary. The Git tree is identical to reviewed commit 467131c92a; unpublished repair iterations were folded while retaining their authored source and test evidence. New CI is running. Packaged Desktop UAT remains a separate gate.

The latest field results are the cross-gateway writer/reviewer workflow, exact Desktop and Signal downloads, a Signal-only revision with Desktop closed, and natural grant-expiry recovery through Telegram. A classic six-Bot group completed a producer-to-reviewer file handoff with exact bytes. After #103638 repaired the profile-policy mismatch, a fresh maximum-size six-Bot group created as hosted and all six Bots settled exactly once.

A hosted six-Bot Group Chat settling six distinct replies on the current field build

A classic Group Chat handing a real Bot-produced file to a remote reviewer

Test evidence and repaired failure cases
  • Desktop baseline: 1,315 tests across 97 files passed before the final storage-order repair; the final affected matrix passes 120 tests, all three TypeScript checks, and lint. These overlapping counts are not additive.
  • Native messaging source: 1,658 tests across 98 files passed without retries. The latest source CI executes the real messaging SDK tests; its workflow change requires the repository's ci-reviewed label.
  • Route source: 580 tests across 41 files passed, with a further publication check of 331 tests across 26 changed test files. These overlapping counts are not additive.
  • The complete backend matrix is being checked on an isolated Linux runtime as well as locally. Mac load exposed timing failures, which remain recorded rather than being counted as passes. Linux search checks pass with 1,000, 10,000, and 50,000 files under the unchanged query budget.
  • All three field gateways now run source da19f696f5, whose backend code is unchanged by the later Desktop-only repairs. Whole-source hygiene and non-root, network-isolated real agent import/tool discovery passed before deployment. Fresh zero-work checks preceded each graceful restart; protected task/delegation records remained unchanged. The final Desktop package is being prepared for acceptance.
  • Actual Telegram UAT retrieved a 2,177-byte Bot-created README from the native Files picker. Its SHA-256 exactly matches the canonical stored artifact. Main and auxiliary model calls pass on all three updated gateways; retained unfinished test records are unchanged across deployment.
  • The Desktop connection check incorporates @bennybuoy's original commit from fix(desktop): probe /api/health on pooled SSH dispatch, not /api/status #97914, with authorship and cherry-pick provenance retained. It stopped the observed false reconnect loop; 47 focused connection tests pass. This composition does not replace or duplicate that source PR.
  • Production and test source modules fit the 2,000-line ceiling. Generated dependency and compatibility inventories are metadata.
  • The latest focused composition gate passes 99 tests, including Retry handoff, messaging attention state, Group Chat controls and the new upstream Slack model picker. The matching signed Desktop package passes 36 focused creation/runtime tests. These are focused updates to the baselines above, not a new additive total.
  • A real two-Bot workshop task produced two versions of the same Markdown filename. Both download correctly in Desktop and match canonical bytes. The reviewer compared the changed participant count/budget and preserved Unicode. A separate Desktop-uploaded brief was retrieved byte-for-byte from Signal with Desktop closed; Signal steering also completed while Desktop was closed.
  • Fresh named-profile cross-gateway creation exposed a duplicated profile URL. Seven failing regression cases preceded the repair; the JSON/binary gate now passes 84 tests and an independent focused review found no blocking issue. The fix is also in fix(bot-mode): sync RoomLink routes across gateway workers #100016 and feat(bot-mode): let Bots hand off files in hosted Group Chats #99159.
  • On the repaired mixed-version field stack, a writer shared a 1,471-byte bilingual Markdown welcome card, a Bot on another gateway reviewed it, and the real Desktop Files download matched the canonical SHA-256 exactly. This verifies actual publication and retrieval, not just a Bot reporting a local pathname.
  • With Desktop closed throughout, Signal then requested a 20-person revision. The writer shared a new 1,500-byte version, the remote reviewer verified it, and Signal delivered both independently selectable versions with exact canonical hashes. The group settled without another client driving it.
  • CI exposed a queued Retry remaining pending behind its cooldown after Stop. The repair makes the existing atomic Stop fence take precedence without starting a retry early: 114 focused tests passed, plus the isolated publication-tree regression. It received an independent review and is also published in the owning messaging layer. The preceding Stop-repair head's executable CI, Docker and Nix checks passed; the aggregate still requires the maintainer-controlled review label.
  • The classic Bot-output candidate passes 106 Python tests and 168 Desktop tests, with all three TypeScript checks. A separate source review found retirement, startup, quota-replay and offline-member gaps; the repaired cases are covered. Its live six-Bot handoff now produces a 2,917-byte Markdown file, delivers it to a remote reviewer, and downloads the exact canonical bytes in Desktop. Backend and client commits remain separately selectable.
  • A fresh 60-second execution grant expired naturally between successful baseline and post-expiry reads. No expiry timestamp, permission or database row was edited to force the result. Telegram then delivered the actual retained file with the canonical SHA-256. This distinguishes durable authorized file access from temporary task execution permission.
  • Native Group Chat navigation now returns to the same status-aware full-width picker, hides actions with no available result, and uses clear verb-led labels with platform-appropriate icons. Ten RED cases preceded the repair; 191 tests across ten files pass, including file/reply revocation timing, plus Ruff, diff and the strict 2K gate. The first full CI run found two stale assertions that still searched for the old Full reply label; the action remained present as Get full reply, and the corrected exact tests pass. Live verification remains before the walkthrough video.
  • fix(bot-mode): match invitations to the target profile policy #103638 reproduces a named-profile catalog mismatch on current main: four policy cases failed before the repair, then 41 tests passed. The live RPC and peer-API catalogs now agree for all three profiles checked. The safety check remains strict; no credential or tool-policy comparison was weakened to make creation succeed.

Fresh real-client UAT is in progress. A recovered writer's late output exposed a missing follow-on reviewer turn; the repair preserves the old task input and creates a fresh recipient turn. It passes 233 tests in the Bot-handoff source and is deployed here. Classic Bot-produced file handoff and hosted six-Bot stress now pass.

The classic messaging consumer now publishes the required commitment and executes queued commands through the existing serial Desktop runner. Recovery tests cover lost acknowledgments, trimmed history, legacy groups, Disband/recreation, delayed session setup, expired command leases, and unresolved file output. A newer input can retire old work without a later retry submitting it again; failed storage writes cannot bypass that protection. These repairs are reviewed and tested, with the final real-client retry still pending. Earlier field receipts remain historical evidence, not certification of every case on this head.

Try The Complete Stack

Check out this PR at the pinned head and use disposable gateways and data. Build Desktop and the backend from the same candidate. Do not assemble moving sibling PRs by hand; the smaller PRs are the review/merge path and this branch is the combined test recipe.

Keep production credentials and data out of automated tests. For field testing, verify the actual recipient's file bytes and one visible result, then repeat with a named remote profile, a reconnect, and a stopped turn. The authority gateway must remain available; this build does not enable unfenced automatic takeover.

The most useful feedback is on missing everyday journeys, regressions from existing Group Chats or single-Bot conversations, confusing recovery controls, and cases that should be included in broader field testing.

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have needs-decision Awaiting maintainer decision before any implementation comp/desktop Electron desktop app (apps/desktop/*) comp/gateway Gateway runner, session dispatch, delivery comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins area/config Config system, migrations, profiles area/docker Docker image, Compose, packaging sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 30, 2026
@liyangbing

Copy link
Copy Markdown

Review: add crash-window tests around artifact settlement

The integration description says upload, commit, acknowledgement, redelivery, restart, and cleanup are idempotent. In the hosted attachment path, those claims cross several different durability boundaries: put() writes the blob before its SQLite row commits; commit_message_with_receipt() changes an uploaded row to committed; retain_event() removes the expiry only after the room event is durable; and prune() commits row/blob metadata deletion before unlinking the filesystem object, with orphan sweeping as recovery.

Suggested focused matrix

Inject a crash or forced exception at each boundary and restart the store/room owner:
1. after the blob write but before the attachment transaction commits — the orphan must be reclaimable and must not bypass the gateway quota on the next upload;
2. after the attachment is committed but before the immutable room event is durable — the expiry/abort path must not retain private bytes;
3. after the event is durable but before retain_event() — reconciliation must retain exactly the IDs named by that event, including a repeated recovery call;
4. after prune() commits metadata deletion but before filesystem unlink — restart cleanup must remove the orphan without deleting a newly-created blob;
5. during duplicate commit/ack/redelivery from two workers — one logical receipt should advance once, while the final read remains authorized to the intended recipient only.

For every row, assert the SQLite state, blob digest/size, room and gateway quota counters, visible event payload, and the next cold-start read. The random blob_id and digest checks make this feasible without snapshotting implementation details. This would turn the draft's strong idempotency claims into regression evidence at the exact crash windows where database durability and filesystem durability can diverge.

@dokterdok
dokterdok force-pushed the feat/bot-mode-group-chat-complete-20260830 branch 2 times, most recently from 2dc1ef4 to 4baab59 Compare August 30, 2026 08:47
@dokterdok dokterdok changed the title feat(bot-mode): complete Group Chat files and Bot handoff feat(bot-mode): complete Group Chat continuity, control, and files Aug 30, 2026
@dokterdok

Copy link
Copy Markdown
Contributor Author

Addressed in 53c72affc4.

The focused matrix now injects and verifies:

  • blob write before attachment-row commit, including cold orphan cleanup and next-upload quota;
  • attachment commit before room-event publication, including expiry/abort cleanup;
  • room event before retain_event(), including repeated reconciliation;
  • prune metadata commit before filesystem unlink, including restart cleanup without deleting a newly-created live blob;
  • concurrent duplicate commit/retain workers, quota counters, visible payload, and recipient-only reads.

retain_event() now changes only still-expiring rows, so duplicate workers advance the logical receipt once instead of merely converging to the same bytes. The complete focused attachment/classic/policy matrix passes 80/80.

The subsequent packaged UAT also exercised image, PDF, generic-file, Bot-generated-file, close/reopen, and cross-gateway handoff paths on real gateways. Thanks for pointing the review at the filesystem/SQLite boundaries rather than only the happy-path RPCs.

@dokterdok
dokterdok force-pushed the feat/bot-mode-group-chat-complete-20260830 branch from ddc950f to 3199a84 Compare September 5, 2026 00:06
dokterdok and others added 22 commits September 5, 2026 02:26
Cold /api/status through a Windows no-mux SSH forward routinely exceeds
the 2.5s dispatch budget, so Desktop retires a live tunnel and respawns.
Use the cheap /api/health route (5s, same as DEFAULT_HEALTH_PROBE_TIMEOUT_MS).
Background liveness still probes /api/status at 10s.

(cherry picked from commit cc6054c)
Persist the reciprocal peer target profile at live-reservation registration and use that durable binding for named room discovery and remote Files. Legacy migration accepts only one unrevoked room/member binding that existed by control creation; natural expiry is not revocation, while missing, reassigned, or ambiguous history stays unbound.

Keep a unique live reservation mandatory for initial control registration and leave RoomLink execution admission, explicit control revocation, authority/member/profile checks, recipient eligibility, publication fencing, and post-fetch revocation unchanged.

Source-control-owner: NousResearch#98073 at 65b2e53 (ported here by 4909ab5).

Source-file-bridge: 4f9678762f (ported here by 1e993be). NousResearch#98072 and NousResearch#99159 do not contain these reciprocal-control/file-access owners.

Test: 220 passed across 8 focused files, one worker, zero retries.
Mark the exact peer control credential locally revoked before contacting the room authority, retaining its bearer after transport failure or malformed acknowledgement so cleanup can be retried after reservation GC. Validate the home DELETE's idempotent revoked=0/1 response and erase only a still-matching terminal row after verified completion.

Match target profile, endpoint, authority/epoch, token, creation, and expiry under an immediate transaction. A concurrently rotated or replaced active row is never removed by stale cleanup. Natural reservation expiry remains independent from revocation.

Source-owner: NousResearch#98073 at 65b2e53, composed above ad35dd4 and Galileo Desktop commit b412108. NousResearch#98072 and NousResearch#99159 do not contain these reciprocal-control owners.

RED: partial remote revoke left the peer control active after home failure; later reservation GC removed the only denial fence.

Test: 239 passed across 10 focused files, one worker, zero retries.
When a shared-store RoomLink scope revocation commits, atomically mark any compatible matching reciprocal peer control revoked in the same SQLite transaction. The optional table is neither imported nor created, so core RoomLink storage remains independent when messaging controls are absent; exact-grant revocation remains unchanged.

This closes the shared-success/profile-failure path before API or RPC cleanup can run. Reservation expiry and unrelated admission GC can no longer reactivate Files, while the revoked control row retains its bearer for verified remote cleanup retry.

Accept additive home DELETE response fields while requiring revoked to be the integer 0 or 1.

Source-owner: NousResearch#98073 at 65b2e53, composed above 1d97ae2 and Galileo Desktop commit 80755ef. NousResearch#98072/NousResearch#99159 have the shared storage file but no reciprocal-control consumer or test.

Test: 101 passed across 8 focused files, one worker, zero retries.
Reproduce the Workshop follow-up failure reported on source269 and preserved at c54b733. Preserve immutable retry admissions and schedule a fresh recipient input after late committed output. Rebuild compacted policy state from bounded receipts, fence completion writes, and expose nonblocking needs_attention status.

Validation: 9 targeted regression cases plus 227 adjacent tests across 10 distinct files pass via scripts/run_tests.sh with zero failures or retries. No controls, Files access, native client, hosts, or publication changes.
Use pending retry and approval actions when settled activity is otherwise idle. Preserve stopping and healthy-running priority, and support older host replies without a needs_attention field. Verified with 65 messaging tests.
Keep retry available after the room settles without hiding healthy ongoing work. Consume both explicit attention and existing pending actions from older hosts. Verified with 25 runtime tests.
Reconcile the upstream Slack model picker into the existing extracted owners. The five relocated methods preserve the upstream AST after facade qualification. Retain the reviewed retry/handoff and attention repairs, and both authorship histories.
Real cross-gateway creation sent /p/member/p/member/v1/room-members/capabilities and fell back on HTTP404. Reuse matching endpoint scope and reject a conflicting explicit profile before I/O. Seven baseline regression failures now pass within an 84-test JSON/binary routing gate. Independent bounded review cleared the change; no grant or redirect policy is loosened.
(cherry picked from commit 76db196cdb6c8851d5eef375d7e441529de503d1)
(cherry picked from commit 179dc0cb1be4b5f0bd9a0894085256f637ef788c)
(cherry picked from commit b9d34be2b8f890df970c7ab0a76d17619049f1ec)
(cherry picked from commit d057f2faf56eef408e0701149913cae5b241d0b3)
(cherry picked from commit bf95af28699aa04f518f143b86a6e30ae90ed68b)
(cherry picked from commit e1d93610a9e0b9e7269cd971b3fd2b115c29fea4)
(cherry picked from commit 416c26fbaac92c652b1bfda015eeac81e614f231)
Compose the Desktop mailbox consumer with classic file handoff. Recover
accepted output under its command lease, keep stopped outcomes durable,
and let newer work continue without resubmitting retired commands.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles area/docker Docker image, Compose, packaging comp/cli CLI entry point, hermes_cli/, setup wizard comp/desktop Electron desktop app (apps/desktop/*) comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins needs-decision Awaiting maintainer decision before any implementation P3 Low — cosmetic, nice to have sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants