Skip to content

feat(presets): drop auto + /pro — flash/pro are the only knobs now#1630

Merged
esengine merged 1 commit into
mainfrom
feat/drop-auto-preset
May 23, 2026
Merged

feat(presets): drop auto + /pro — flash/pro are the only knobs now#1630
esengine merged 1 commit into
mainfrom
feat/drop-auto-preset

Conversation

@esengine

Copy link
Copy Markdown
Owner

Why

Two surfaces in the loop could spend money behind the user's back:

  1. auto preset — flash would self-escalate to pro mid-turn via the <<<NEEDS_PRO>>> marker. The decision was opaque, the cost delta wasn't surfaced clearly, and a stuck loop on auto could quietly bill at pro pricing for many iters.
  2. /pro one-shot — armed for the next turn and disarmed after, but combined with /loop, a steer queue, or an AFK session it could fire multiple pro turns on prompts the user never saw run.

Both are gone. From this PR forward the model knob is flash or pro, picked explicitly. The user always knows which model is on.

What

PresetName is now exactly "flash" | "pro" — no auto, no smart/fast/max legacy aliases in the type. Old configs holding any of those values keep loading: loadPreset and the loose-input resolvePreset / canonicalPresetName silently coerce anything that isn't flash/pro to flash. No legacy migration notice — old preset: "auto" just opens as flash.

Removed

  • CacheFirstLoopOptions.autoEscalate, loop.autoEscalate, the streaming-time NEEDS_PRO buffer/flush, the post-call NEEDS_PRO retry, src/loop/escalation.ts, the loop.flashEscalation i18n string.
  • loop.armProForNextTurn, loop.disarmPro, loop.proArmed, loop.escalatedThisTurn, loop.currentCallModel, the _escalateThisTurn / _proArmedForNextTurn state, the loop.proArmed warning yield.
  • /pro slash command + handler + i18n.
  • Dashboard proNext field on POST /api/settings + ctx.setProNextLive + the proNext / proArm / proArmed / proNextNote i18n bundle.
  • StatsPanel's pro pill (escalated / proArmed props + rendering).
  • ModelPicker's currentAutoEscalate prop and matching detector.
  • usePresetMode's proArmed / turnOnPro state.
  • ResolvedDefaults.autoEscalate, handleWarningEvent's setTurnOnPro hook, AppProps.autoEscalate / ChatOptions.autoEscalate.
  • The "auto" preset card in both desktop and dashboard Settings → Models.

Kept

  • /preset flash and /preset pro work as before.
  • /preset auto (and auto as a --preset flag) accept the value but route to usage error / flash respectively — no surprise upgrade.

Verify

  • npm run typecheck (root + dashboard)
  • npm run lint (only pre-existing welcome-banner warning)
  • npm run test — 3576 pass
  • npm run verify — build + lint + typecheck + tests all green
  • Manual: ~/.reasonix/config.json with "preset": "auto" loads as flash, no warning row, model id reads deepseek-v4-flash
  • Manual: /preset auto shows the usage hint; /preset flash and /preset pro switch live
  • Manual: /pro returns "unknown slash command"
  • Manual: Settings → Models in both desktop and dashboard show two cards (flash, pro), no Compute → /pro one-shot block

47 files, net -669 lines.

Auto-escalation (flash → pro via the `<<<NEEDS_PRO>>>` marker) and the
one-shot `/pro` arming were both surfaces that could spend money behind
the user's back: a turn that ran on flash could silently re-bill on pro,
and `/pro` plus an idle session compounded the same risk. Both are gone.

PresetName is now exactly `"flash" | "pro"`. Old configs holding
`auto` / `smart` / `fast` / `max` keep loading: `loadPreset` and the
loose-input `resolvePreset` / `canonicalPresetName` silently coerce
anything that isn't `flash`/`pro` to `flash`. No legacy migration
notice — the user just gets the new safe default.

Surface dropped:
- `CacheFirstLoopOptions.autoEscalate`, `loop.autoEscalate`, the
  streaming-time NEEDS_PRO buffer/flush, the post-call NEEDS_PRO retry,
  `src/loop/escalation.ts`, the `loop.flashEscalation` i18n string.
- `loop.armProForNextTurn`, `loop.disarmPro`, `loop.proArmed`,
  `loop.escalatedThisTurn`, `loop.currentCallModel`, the `_escalateThisTurn`
  / `_proArmedForNextTurn` state, the `loop.proArmed` warning yield.
- `/pro` slash command + handler + i18n.
- Dashboard `proNext` field on `POST /api/settings` + ctx.setProNextLive
  + the proNext / proArm / proArmed / proNextNote i18n bundle.
- StatsPanel's pro pill (escalated / proArmed props + rendering).
- ModelPicker's `currentAutoEscalate` prop and detect.
- usePresetMode's proArmed / turnOnPro state.
- ResolvedDefaults.autoEscalate, handleWarningEvent's setTurnOnPro hook,
  AppProps.autoEscalate / ChatOptions.autoEscalate.
- "auto" preset card in both desktop and dashboard Settings → Models.

Tests updated:
- tests/presets.test.ts: legacy + unknown values coerce to flash.
- tests/resolve.test.ts: legacy auto/smart/fast/max coerce silently.
- tests/slash.test.ts: `/preset auto` returns usage; `/preset flash` /
  `/preset pro` keep working; arg-picker enum is `["flash", "pro"]`.
- tests/loop.test.ts: NEEDS_PRO describe block and the proArm/disarm
  tests are gone with the features.
- tests/server-dashboard.test.ts: proNext field is gone from the live
  callback test.
- tests/preset-effort-isolation.test.ts: only flash/pro iterated.
- tests/ui-slash-suggestions.test.tsx: advanced-group count 11 → 10.

Verify: tsc clean (root + dashboard), biome clean (only pre-existing
welcome-banner warning), 3576 tests pass.

Net -669 lines.
@esengine esengine force-pushed the feat/drop-auto-preset branch from 0753078 to 3b62591 Compare May 23, 2026 14:19
@esengine esengine merged commit 161d6ec into main May 23, 2026
4 checks passed
@esengine esengine deleted the feat/drop-auto-preset branch May 23, 2026 14:45
esengine pushed a commit that referenced this pull request May 24, 2026
…moved, persisted usage stats, plan dispatch gate

Headline themes:
- Desktop: bundle the CLI-hosted React dashboard, retire Tauri+Preact duplicate (#1418)
- Config: drop preset abstraction; flash/pro are direct model selections (#1657, #1630)
- Stats: persist cumulative usage to session meta + auto-restore on startup (#1667, #1680, #1643, #1628)
- Plans: editMode="plan" enforced at the ToolRegistry dispatch gate (#1681); step advance fix (#1629)
- Context: fold once at turn start, drop pre-flight + byte-ceiling (#1642, #1646); collapsible compacted card (#1649)
- Subagents: per-skill flash/pro override + Settings UI (#1632)
- Desktop polish: sidebar drag-resize (#1688), responsive collapse (#1585), copy/edit overlay + msg-history nav (#1645), Esc closes modal not turn (#1685), QQ tab isolation (#1672), DiffCard for edits (#1662), theme-aware highlighting (#1655), system events toggle (#1654/#1650), macOS TCC inheritance (#1614), dashboard.enabled (#1612)
- Dashboard polish: persistent session URL (#1586, #1589, #1599), theme-aware highlighting (#1664), IME confirm-enter guard (#1689), code-fence lang fix (#1677), vendor chunk split (#1587), markdown table h-scroll (#1562)
- TUI: Alt+S input stash/recall; static history isolated from input rerenders (#1635); legacy mouse drop (#1637, #1648); multi-edit gated in review (#1647)
- Diff: SplitDiff column border holds under CJK (#1686)
- MCP: workspace roots passed to servers (#1625); codeCommand honors mcpServers (#1603)
- Config plumbing: (baseUrl, apiKey) resolved as a tuple (#1658); stale model id self-heal (#1663)

See CHANGELOG for the full list.
esengine pushed a commit that referenced this pull request May 25, 2026
Three stale-doc fixes:

- ARCHITECTURE.md §4.3 — replace removed /pro single-turn arming with the
  current /model flash|pro + settings.json model selection. Note the
  removal in 0.50.0 (#1657, #1630).
- ARCHITECTURE.md §4.4 — replace the never-existed FAILURE_ESCALATION_THRESHOLD
  counter with the actual <<<NEEDS_PRO>>> model self-report mechanism. No
  failure-counter; purely LLM-initiated, no-op on pro tier.
- benchmarks/real-world-cache/README.md — fix 10× pricing error in
  v4-flash cache-hit ($0.028 → $0.0028) and entirely wrong v4-pro pricing
  ($0.139/1.667/3.333 → $0.003625/0.435/0.87). Recalculated cost tables;
  headline 99.82% hit ratio unchanged, savings now correctly show ~97.7%
  (flash) / ~98.9% (pro).

Thanks @FriendsHL for catching this — the benchmark pricing in particular
is the public cache-first defense link, the old numbers would have been
embarrassing.
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