Skip to content

feat(desktop): configurable group chat round cap + model-aware limits + token budget guard - #97326

Closed
beplee wants to merge 2 commits into
NousResearch:bb/bot-mode-design-systemfrom
beplee:feat/desktop-round-cap-v2
Closed

beplee wants to merge 2 commits into
NousResearch:bb/bot-mode-design-systemfrom
beplee:feat/desktop-round-cap-v2

Conversation

@beplee

@beplee beplee commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add group-chat-config.ts: config.yaml-driven group_chat.* settings + free-model detection
  • Make GROUP_CHAT_MAX_ROUNDS config-aware: free models (:free suffix or free_models[] allowlist) get unlimited rounds up to HARD_CAP=20, paid models default to max_rounds: 3
  • Add token-budget guard: cumulative room-log tokens exceeding group_chat.token_budget (default 80k chars) force exitKind='capped' independent of round count — the real safety net for pathological cascades
  • Add getGroupChatConfig(), isFreeModel(), getEffectiveRoundCap(), getCurrentModelName() helpers
  • Add config.yaml schema in cli-config.yaml.example under group_chat:

Why

Hardcoded 3-round cap is too tight for free-model rooms (where API cost is zero) and too loose for paid-model rooms (where each round burns real money). A single config block drives everything automatically.

Config

group_chat:
  max_rounds: 3              # paid models
  max_rounds_free: null      # null = unlimited (HARD_CAP=20 backstop)
  token_budget: 80000        # hard ceiling per drive (chars, ~20k tokens)
  free_models:               # quality-tier allowlist
    - upstage/solar-pro4
    - meituan/longcat-2.0
    - tencent/hy3
  hard_cap: 20               # absolute ceiling even for free models

Safety

  • Token budget is the real backstop — fires regardless of model type or round count
  • HARD_CAP=20 prevents unbounded free-model cascades (20 rounds × 6 bots = 120 messages max)
  • Paid models always capped at max_rounds (default 3)
  • exitKind='capped' logged to activity feed for every termination path

Test plan

  • Paid model → 3-round cap fires
  • Free model (allowlist) → 20-round cap fires
  • Token budget exhaustion → mid-drive cap fires
  • Model switch mid-drive → cap re-evaluates
  • 6-bot free room → halts cleanly at token budget
  • Empty free_models + :free suffix → allowlist is sole gate (no bypass)

Refs: #96726, #96842 (closed — superseeded by this port to new module structure)

… + token budget guard

- Add group-chat-config.ts: config.yaml-driven group_chat settings + free-model detection
- Make GROUP_CHAT_MAX_ROUNDS config-aware: free models get unlimited rounds (up to HARD_CAP=20), paid models default 3
- Add token-budget guard: cumulative room-log tokens exceeding group_chat.token_budget (default 80k chars) force exitKind='capped' independent of round count
- Detect free models via :free suffix or free_models[] allowlist
- Add config.yaml schema in cli-config.yaml.example under group_chat:

Refs: NousResearch#96726 (maintainer flagged this as the follow-up needed for the new Bot Mode modules)
@alt-glitch alt-glitch added type/feature New feature or request comp/desktop Electron desktop app (apps/desktop/*) area/config Config system, migrations, profiles P3 Low — cosmetic, nice to have sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 28, 2026
- Remove unused GROUP_CHAT_MAX_ROUNDS import (unused-imports/no-unused-imports)
- Reorder named imports: getCurrentModelName before getGroupChatConfig (perfectionist/sort-named-imports)

Fixes PR NousResearch#97326 CI job 98930161351 JS & TS checks failure.
@OutThisLife
OutThisLife deleted the branch NousResearch:bb/bot-mode-design-system August 28, 2026 20:06
@Enough1122

Copy link
Copy Markdown
Contributor

AI code review — automated review for reference; please use your judgment.

Overall: Feature that makes GROUP_CHAT_MAX_ROUNDS=3 config-driven and model-aware: free models ( :free or free_models[] allowlist) get hard_cap=20 up to unlimited, paid models stay max_rounds=3, plus a hard token-budget guard (80k chars ≈20k tokens) that exits capped independent of rounds. Addresses #96726 follow-up and #96842.

What it does

  • apps/desktop/src/plugins/hermes-bots/group-chat-config.ts:59 new module: GroupChatConfig (max_rounds, max_rounds_free=null, hard_cap=20, token_budget=80000, free_models:[]), getGroupChatConfig() via host.request('config.get',{key:group_chat}) with defaults, isFreeModel(name,cfg) (/:free$/i or substring allowlist), getEffectiveRoundCap (null/Infinity→hard_cap, else min(cap,hard_cap)), getCurrentModelName() via model.options, estimateTokens≈len/4.
  • apps/desktop/src/plugins/hermes-bots/group-rounds.ts:502 resolves effectiveCap at drive start and token-budgets each round: roomLogAtRoundStart → driveTokens = sum(estimateTokens(e.text)), if >= tokenBudgetexitKind=capped + recordGroupActivity capped and return; loop now for (round < effectiveCap).
  • cli-config.yaml.example:1554 documents group_chat: block.

Non-blocking notes

  • Config read is async once per drive — paid-model cap evaluates before first round; mid-drive model switch only re-evaluated next drive (not per-round re-read) — acceptable as drives short; getCurrentModelName remains available for future per-round re-eval.
  • estimateTokens≈chars/4 is rough lower-bound; token_budget default 80k chars labeled chars but treated as token budget — ensure docs clarify it's char-based budget (≈20k tokens).
  • free_models[] substring match is case-insensitive includes — tencent/hy3 will match tencent/hy3-preview etc.; allowlist semantics vs exact ID — document substring behavior so operators don't expect exact match.
  • Test plan checkboxes are manual; consider adding vitest for isFreeModel/getEffectiveRoundCap/budget guard.

Non-blocking — please use your judgment.

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 comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades 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.

4 participants