feat(desktop): configurable group chat round cap + model-aware limits + token budget guard - #96842
feat(desktop): configurable group chat round cap + model-aware limits + token budget guard#96842beplee wants to merge 2 commits into
Conversation
…dget guard - Replace hardcoded GROUP_CHAT_MAX_ROUNDS constant with config.yaml-driven group_chat.max_rounds (default 3, range 1-20) - Add model-aware cap: free models (:free suffix or free_models list) use group_chat.max_rounds_free (null = unlimited, clamped to HARD_CAP=20) - Add token-budget guard: cumulative room-log tokens exceeding group_chat.token_budget (default 80k) 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: - Update behavioral model comment to reference effectiveCap Refs: NousResearch#96553
GROUP_CHAT_MAX_ROUNDS and its four siblings carry over at the values plugin.js shipped, so no rebase inherits a behavior change on top of a rewrite. Making them configurable is live contributor work — #92213 for per-room limits, #96842 for config plus a token budget — and both want the same single seam, so say so where the constants are instead of adding a config hook this PR has no consumer for.
Closure rationaleThis PR is closed as written because its target file () is deleted by #96726 (OutThisLife, "Rebuild Bot Mode on the app's design system", 230 files, 36k+/32k- diff). #96726 is moving toward merge and the file this PR patches will not exist on after that merge. The feature itself is still needed. #96726 hardcodes at and the maintainer's comment on #96726 explicitly flags #96842 as the gap-filler:
What comes next: port the configurable round cap + model-aware limits + token-budget guard to the new module surface (, , ) after #96726 merges. The design work is already done in (branch ). Slot freed — we can open the port PR cleanly when #96726 lands and we have a slot. |
A Bot Mode room stops after 3 serial rounds and 10 member messages. That suits a quick two-bot exchange and cuts short a workflow whose hops are genuinely serial: a coordinator triaging to a domain expert, to a data operator, and back needs more passes than three, so the room reports 'turn stopped at the round/message cap' with a bot still holding an addressed handoff. Read the ceilings from a group_chat block in config.yaml, falling back to today's values when it is absent, so the person paying for the model calls decides what a room may spend. Config is advisory, never authoritative: each value is clamped to a hard ceiling (20 rounds / 100 messages / 20 continuations), and anything below 1 or unparseable reads as unset rather than as zero. A typo can neither silence a room nor uncap it. The limits resolve once at plugin load and are snapshotted per drive rather than read inside the round loop, which is hot; a gateway round-trip there would be a stall the user feels. A config edit reaches a room on its next send. Reading fails silently to the shipped defaults, because a room that runs beats a room that refuses to start because config could not be read. Ports the design from NousResearch#96842 (beplee), which was closed unmerged when NousResearch#96726 deleted the plugin.js it patched, onto the new modules. Uses the existing config.get 'full' key rather than adding a gateway method. Per-room overrides (NousResearch#92213) can layer on the same seam. Refs NousResearch#98004, NousResearch#96842, NousResearch#89545
GROUP_CHAT_MAX_ROUNDS and its four siblings carry over at the values plugin.js shipped, so no rebase inherits a behavior change on top of a rewrite. Making them configurable is live contributor work — NousResearch#92213 for per-room limits, NousResearch#96842 for config plus a token budget — and both want the same single seam, so say so where the constants are instead of adding a config hook this PR has no consumer for.
Summary
GROUP_CHAT_MAX_ROUNDSconstant with config.yaml-drivengroup_chat.max_rounds(default 3, range 1-20):freesuffix orfree_modelsallowlist) usegroup_chat.max_rounds_free(null = unlimited, clamped toHARD_CAP=20)group_chat.token_budget(default 80k chars) forceexitKind='capped'independent of round count — the real safety net for pathological cascadesgetGroupChatConfig(),isFreeModel(),getEffectiveRoundCap(),getCurrentModelName()helperscli-config.yaml.exampleundergroup_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
Safety
HARD_CAP=20prevents unbounded free-model cascades (20 rounds × 6 bots = 120 messages max)max_rounds(default 3)exitKind='capped'reason logged for every termination pathTest plan
free_models+:freesuffix → allowlist is sole gate (no bypass)Refs: #96553