Skip to content

Add opt-in "Extended rounds" for Bot Mode group-chat rooms - #1

Merged
RFingAdam merged 2 commits into
feat/kanban-completion-guards-and-oauth-sanitizefrom
feat/bot-mode-extended-rounds
Aug 23, 2026
Merged

RFingAdam merged 2 commits into
feat/kanban-completion-guards-and-oauth-sanitizefrom
feat/bot-mode-extended-rounds

Conversation

@RFingAdam

@RFingAdam RFingAdam commented Aug 23, 2026 •

Copy link
Copy Markdown
Owner

What changed

Bot Mode's group-chat room loop (apps/desktop/src/plugins/hermes-bots/plugin.js) gets an opt-in "Extended rounds" setting:

  • Default (OFF): exact upstream stock behavior — 3 rounds / 10 messages / no wall-clock cap. A fresh install of this fork is byte-identical to NousResearch/hermes-agent until a user explicitly opts in.
  • ON: raised ceilings + a new protection — 24 rounds / 120 messages, plus a 30-minute wall-clock cap that stock never had.
  • New UI toggle in the Bots pane header (stopwatch icon, next to the activity-toast bell).
  • Both the toggle and an optional fine-tune override ({ maxRounds, maxMessages, wallClockMinutes }, hard-clamped, malformed/out-of-range input rejected per-field) persist via plugin storage.

Why the redesign (this supersedes the first commit on this branch)

The first commit on this branch just raised the shipped defaults globally. Adam's direction was better: keep Nous's own behavior as the untouched default, and make "run longer" an explicit, protected opt-in — so this fork never silently diverges from upstream for anyone who doesn't ask for it, and the extended path gets its own independent safety net rather than just bigger numbers.

Safety

  • Flipping extended mode off always restores exact stock constants — no override can leak through.
  • The wall-clock cap is new and independent of the existing "everyone passed this round" settle exit, which is conversation-shaped (only fires when literally every member passes/times out). Extended mode's much higher round ceiling widens the exposure window if a member ever got stuck producing real-looking, non-settling text every turn — the wall-clock deadline bounds worst-case cost/duration regardless of whether that heuristic ever fires.
  • Override values are clamped to hard ranges (rounds 1-100, messages 1-500, wall-clock 1s-2h) and rejected (not silently clamped to a boundary) when out of range or malformed.

Testing

  • Rewrote the fork's regression tests for the new design: default-is-stock, toggle raises/restores correctly, override clamps per-field in both directions, an end-to-end test that a tuned-down extended cap actually stops the loop, an end-to-end test that the wall-clock deadline ends a non-settling drive early via real setTimeout-based turn latency, and a test proving stock mode ignores a staged extended-mode override entirely.
  • Fixed the test harness's prompt.submit mock to await turnScript (previously sync-only, silently no-op'd on an async turnScript — needed for the real-latency wall-clock test).
  • Full hermes-bots plugin suite: 244/244 passing (node --test src/plugins/hermes-bots/tests/*.test.mjs).
  • Secret scan clean on both changed files.

Scope note

Targets our fork's own working branch (feat/kanban-completion-guards-and-oauth-sanitize, which carries pre-existing local kanban/OAuth patches), not NousResearch/hermes-agent upstream main — this is a fork-local feature we're managing ourselves, not (yet) proposed upstream.

Not in scope here

The gateway-side per-platform require_mention mention-gate (Discord/Telegram/etc adapters) that production group chats actually run on is a different mechanism (per-message gating, not a round-count ceiling) and isn't touched by this PR.

…ake live-tunable

Upstream's Bot Mode group-chat room loop hard-caps at GROUP_CHAT_MAX_ROUNDS=3
and GROUP_CHAT_MAX_MESSAGES=10 per user send. That's tuned for a quick
multi-bot exchange, not letting a room of specialist bots (Ironhaven Exec,
Engineering Ops, Bounty Ops, etc.) actually work a problem turn-over-turn
until it settles -- our real usage keeps hitting the ceiling mid-task with
work still in flight, forcing a manual re-send to get another 3 rounds.

Changes:
- GROUP_CHAT_MAX_ROUNDS 3 -> 24, GROUP_CHAT_MAX_MESSAGES 10 -> 120 (both
  now `let`, not `const`).
- New applyGroupChatSettings(value) + getGroupChatCeilings(): both
  ceilings are live-tunable via ctx.storage('group-chat-settings') =
  { maxRounds, maxMessages }, clamped to sane bounds (1-500 rounds,
  1-2000 messages) and silently ignoring malformed/out-of-range input --
  a bad stored value can never brick the room loop. Hydrated at plugin
  registration alongside the existing bot-meta/activity-toasts/
  group-chats storage reads.
- No settings-panel UI wired yet (this plugin SDK version has no generic
  settings-panel registration area to hook into) -- tuning today means
  writing directly to ctx.storage, not a toggle in the Bots pane. A
  proper settings UI is a natural follow-up, not required for the
  ceiling raise itself to take effect.

Deliberately did NOT touch the anti-cascade design: the "everyone passed
this round" settle exit is unchanged and remains the real safety valve
against a runaway/looping room -- a genuinely stuck room still stops
within one round regardless of how high these ceilings go. This raises
how long a room is ALLOWED to keep working, not how long it's forced to.

Tests: 5 new regression tests (raised-defaults sanity, settings-override
accept/clamp/malformed-input, and an end-to-end enforcement check that a
tuned-down cap actually stops the loop) plus the existing hard-caps test
updated to read the live ceiling via getGroupChatCeilings() instead of
the now-mutable constant. Full hermes-bots plugin suite: 241/241 passing.

Not changed: the gateway-side per-platform require_mention gate (Discord/
Telegram/etc adapters) that Adam's actual production group chats run on --
that's a different, per-message mention-gate mechanism, not a round-count
ceiling, and is out of scope for this change. Tracked as a likely
follow-up once this round-cap raise is proven out in the desktop rooms.
…lt change

Redesigned the previous commit's approach per Adam's direction: upstream's
stock behavior (3 rounds / 10 messages, no wall-clock cap) stays the
untouched DEFAULT for every install -- a fresh clone of this fork behaves
byte-identically to NousResearch's hermes-agent until a user explicitly
opts in. Longer-running multi-bot rooms (what our Ironhaven Exec /
Engineering Ops / Bounty Ops / General Workbots setups actually need) are
now a deliberate, protected opt-in, not the blanket global raise the prior
commit shipped.

Design:
- GROUP_CHAT_STOCK_MAX_ROUNDS=3 / GROUP_CHAT_STOCK_MAX_MESSAGES=10: exact
  upstream constants, always available regardless of the toggle.
- GROUP_CHAT_EXTENDED_MAX_ROUNDS=24 / _MAX_MESSAGES=120 /
  _WALL_CLOCK_MS=30min: only take effect once a user flips "Extended
  rounds" on (persisted via ctx.storage('group-chat-extended-mode'),
  default false). Flipping it back off always restores exact stock
  behavior -- no override can leak through.
- New protection extended mode has that stock never had: an independent
  wall-clock deadline on the whole room-turn drive. The existing "everyone
  passed this round" settle exit is conversation-shaped (only fires when
  literally every member passes/times out) -- running many more rounds
  widens the exposure window if a member ever gets stuck producing
  real-looking, non-settling text every turn. The wall-clock cap bounds
  worst-case cost/duration independent of whether that heuristic ever
  fires.
- Optional fine-tuning via ctx.storage('group-chat-extended-override') =
  { maxRounds, maxMessages, wallClockMinutes | wallClockMs }, hard-clamped
  (rounds 1-100, messages 1-500, wall-clock 1s-2h) with per-field
  rejection (not silent clamping to a boundary) of anything out of range
  or malformed -- a bad stored value can never brick the loop or escape
  the safe ranges. An override only has any effect while extended mode is
  actually on.
- New UI toggle in the Bots pane header (stopwatch icon, next to the
  activity-toast bell) makes this a real discoverable setting, not
  storage-only.

$groupChatExtendedMode's atom() call is deliberately declared up near
$activityToasts rather than down in the group-chat section, because
soul-protocol-backfill.test.mjs vm-evals a fixed line-range slice of this
file (botHandle .. the human-readable-row-helpers marker) with no `atom`
in scope -- keeping every top-level atom() call above that slice avoids
breaking it. Documented inline at both the declaration and the removed
site.

This is a forward-only fix commit on top of the previous one (never
force-pushed/rewrote it) -- see hard rule 3 in github-rfingadam-pr: no
history rewrite even on our own fork's own feature branch.

Tests: rewrote the fork-specific regression tests to match the new
stock-default/opt-in design (default-is-stock, toggle-raises-and-restores,
override-clamps-per-field-both-directions, a real end-to-end enforcement
test that a tuned-down extended cap stops the loop, a real end-to-end test
that the wall-clock deadline ends a non-settling drive early via genuine
setTimeout-based turn latency, and a test proving stock mode ignores a
staged extended-mode override entirely). Fixed the test harness's
prompt.submit mock to await turnScript (previously synchronous-only,
which silently no-op'd on an async turnScript). Full hermes-bots plugin
suite: 244/244 passing (`node --test src/plugins/hermes-bots/tests/*.test.mjs`).
Secret scan clean.
@RFingAdam RFingAdam changed the title Raise Bot Mode group-chat round/message ceilings, make live-tunable Add opt-in "Extended rounds" for Bot Mode group-chat rooms Aug 23, 2026
@RFingAdam
RFingAdam merged commit 791fc66 into feat/kanban-completion-guards-and-oauth-sanitize Aug 23, 2026
@RFingAdam

Copy link
Copy Markdown
Owner Author

Post-merge verification — workstation (swamp) desktop rollout

Repointed this workstation's checkout (/home/swamp/.hermes/hermes-agent) to the fork and rebuilt Desktop (hermes desktop --force-build); install stamp 791fc6673d09. Drove the packaged renderer over a loopback CDP port and confirmed the feature end-to-end:

  • Toggle works and persists. Stopwatch in the Bots roster header; aria-label flips Enable ⇄ Disable extended group-chat rounds; state stored at hermes.plugin.hermes-bots.group-chat-extended-mode and survives restart. Flipping it back off restores exact stock behavior.
  • Ceilings confirmed live. Stock 3 rounds / 10 messages / no wall-clock; extended 24 / 120 / 30 min. The settle-on-all-pass exit still fires under extended.
  • Override lever works: group-chat-extended-override ({maxRounds, maxMessages, wallClockMinutes|wallClockMs}) raises ceilings with no rebuild.

One UX/docs note worth surfacing: in rooms with 5 bots the message cap (10), not the round cap (3), is the effective wall — it bites after 2 rounds. A user reads "3 max" in the tooltip but sees the drive stop at 2 rounds / 10 messages. Might be worth wording the stock tooltip around messages, or scaling the message cap with roster size. Extended's 120 makes this a non-issue there.

Rollout follow-ups (not this PR):

  • 3080 PC (10.27.27.10) still builds from Nous main — no stopwatch yet; needs the same repoint.
  • The fork branch is ~755 commits behind upstream/main, so the desktop "behind main" badge now counts against the fork's main and reads +1032. Expected given how the count works (HEAD..origin/main); merging upstream/main into the feature branch clears it.

RFingAdam added a commit that referenced this pull request Aug 26, 2026
Bot Mode's group-chat room loop (`apps/desktop/src/plugins/hermes-bots/plugin.js`) gets an opt-in **"Extended rounds"** setting:

- **Default (OFF): exact upstream stock behavior** — 3 rounds / 10 messages / no wall-clock cap. A fresh install of this fork is byte-identical to `NousResearch/hermes-agent` until a user explicitly opts in.
- **ON: raised ceilings + a new protection** — 24 rounds / 120 messages, plus a 30-minute wall-clock cap that stock never had.
- New UI toggle in the Bots pane header (stopwatch icon, next to the activity-toast bell).
- Both the toggle and an optional fine-tune override (`{ maxRounds, maxMessages, wallClockMinutes }`, hard-clamped, malformed/out-of-range input rejected per-field) persist via plugin storage.

The first commit on this branch just raised the shipped defaults globally. Adam's direction was better: keep Nous's own behavior as the untouched default, and make "run longer" an explicit, protected opt-in — so this fork never silently diverges from upstream for anyone who doesn't ask for it, and the extended path gets its own independent safety net rather than just bigger numbers.

- Flipping extended mode off always restores exact stock constants — no override can leak through.
- The wall-clock cap is new and independent of the existing "everyone passed this round" settle exit, which is conversation-shaped (only fires when literally every member passes/times out). Extended mode's much higher round ceiling widens the exposure window if a member ever got stuck producing real-looking, non-settling text every turn — the wall-clock deadline bounds worst-case cost/duration regardless of whether that heuristic ever fires.
- Override values are clamped to hard ranges (rounds 1-100, messages 1-500, wall-clock 1s-2h) and rejected (not silently clamped to a boundary) when out of range or malformed.

- Rewrote the fork's regression tests for the new design: default-is-stock, toggle raises/restores correctly, override clamps per-field in both directions, an end-to-end test that a tuned-down extended cap actually stops the loop, an end-to-end test that the wall-clock deadline ends a non-settling drive early via real `setTimeout`-based turn latency, and a test proving stock mode ignores a staged extended-mode override entirely.
- Fixed the test harness's `prompt.submit` mock to `await turnScript` (previously sync-only, silently no-op'd on an async turnScript — needed for the real-latency wall-clock test).
- Full `hermes-bots` plugin suite: **244/244 passing** (`node --test src/plugins/hermes-bots/tests/*.test.mjs`).
- Secret scan clean on both changed files.

Targets our fork's own working branch (`feat/kanban-completion-guards-and-oauth-sanitize`, which carries pre-existing local kanban/OAuth patches), not `NousResearch/hermes-agent` upstream `main` — this is a fork-local feature we're managing ourselves, not (yet) proposed upstream.

The gateway-side per-platform `require_mention` mention-gate (Discord/Telegram/etc adapters) that production group chats actually run on is a different mechanism (per-message gating, not a round-count ceiling) and isn't touched by this PR.

(cherry picked from commit 791fc66)
RFingAdam added a commit that referenced this pull request Aug 26, 2026
…esets

Replace the install-wide stock/extended ceiling toggle as the only governor
with optional per-room modes that override it when set. Unset rooms keep
exact prior global-toggle behavior (zero regression).

- rooms[name].mode: 'build' | 'decide' | 'standing' | unset
- Message budget scales as messagesPerMemberPerRound * members * rounds
  (fixes the PR #1 5-bot stock bug where a flat 10-msg cap died at round 2)
- decide: chat-only prompt rule + deterministic system summary on hard cap
- build: long ceilings, tool-capable (prompt does not restrict tools)
- standing: moderate multi-trigger coordination ceilings
- Room-header dropdown to set/clear mode (persists on the room record)

Kanban: t_ee2e6fe4
(cherry picked from commit e212071)
RFingAdam added a commit that referenced this pull request Aug 26, 2026
…esets (#2)

* feat(desktop/hermes-bots): per-room build/decide/standing Bot Mode presets

Replace the install-wide stock/extended ceiling toggle as the only governor
with optional per-room modes that override it when set. Unset rooms keep
exact prior global-toggle behavior (zero regression).

- rooms[name].mode: 'build' | 'decide' | 'standing' | unset
- Message budget scales as messagesPerMemberPerRound * members * rounds
  (fixes the PR #1 5-bot stock bug where a flat 10-msg cap died at round 2)
- decide: chat-only prompt rule + deterministic system summary on hard cap
- build: long ceilings, tool-capable (prompt does not restrict tools)
- standing: moderate multi-trigger coordination ceilings
- Room-header dropdown to set/clear mode (persists on the room record)

Kanban: t_ee2e6fe4

* ci: retrigger checks (never ran on this PR)
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.

1 participant