mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-09 08:21:50 +00:00
fix(credits): let the "grant spent" notice yield on the next prompt (#40367)
credits.grant_spent is a one-time "your monthly grant is used up, you're now on top-up" heads-up, but it was sticky — it camped the TUI status bar until the grant refilled, so a user with healthy top-up saw "Grant spent · $990 top-up left" indefinitely. Treat it like the usage-band notice: flash once, then clear on the next prompt (startMessage). Depletion stays sticky (you actually can't make requests). The Python `active` latch keeps the key, so it won't re-fire next turn.
This commit is contained in:
parent
fcb1944b4f
commit
c79b6f23e6
2 changed files with 25 additions and 10 deletions
|
|
@ -4,10 +4,11 @@ import { turnController } from '../app/turnController.js'
|
|||
import { resetTurnState } from '../app/turnStore.js'
|
||||
import { getUiState, patchUiState, resetUiState } from '../app/uiStore.js'
|
||||
|
||||
// turnController.startMessage() treats the usage-band notice (credits.usage) as
|
||||
// "show until next prompt": a 50/75/90 heads-up flashes, then yields when the next
|
||||
// turn starts. Depletion (and other notices) are sticky until the policy clears them.
|
||||
describe('turnController.startMessage — usage-band notice clears on next prompt', () => {
|
||||
// turnController.startMessage() treats "flash and yield" notices (the usage-band
|
||||
// credits.usage and the one-time credits.grant_spent transition) as "show until next
|
||||
// prompt": they flash once, then yield when the next turn starts. Depletion (and
|
||||
// other notices) are sticky until the policy clears them.
|
||||
describe('turnController.startMessage — flash-and-yield notices clear on next prompt', () => {
|
||||
beforeEach(() => {
|
||||
resetUiState()
|
||||
resetTurnState()
|
||||
|
|
@ -22,6 +23,16 @@ describe('turnController.startMessage — usage-band notice clears on next promp
|
|||
expect(getUiState().notice).toBeNull()
|
||||
})
|
||||
|
||||
it('clears a standing credits.grant_spent notice when a new turn starts', () => {
|
||||
// One-time "you've crossed onto top-up" heads-up — shouldn't camp the bar
|
||||
// (e.g. "Grant spent · $990 top-up left" with plenty of top-up remaining).
|
||||
patchUiState({
|
||||
notice: { key: 'credits.grant_spent', kind: 'sticky', level: 'info', text: '• Grant spent · $990.00 top-up left' }
|
||||
})
|
||||
turnController.startMessage()
|
||||
expect(getUiState().notice).toBeNull()
|
||||
})
|
||||
|
||||
it('leaves a sticky credits.depleted notice across a new turn', () => {
|
||||
patchUiState({
|
||||
notice: { key: 'credits.depleted', kind: 'sticky', level: 'error', text: '✕ Credit access paused · run /usage for balance' }
|
||||
|
|
|
|||
|
|
@ -907,12 +907,16 @@ class TurnController {
|
|||
this.toolTokenAcc = 0
|
||||
this.interrupted = false
|
||||
this.persistedToolLabels.clear()
|
||||
// Usage-band notices (credits.usage) are "show until next prompt": a 50/75/90
|
||||
// heads-up should flash and then yield, not camp the bar. Clear it as a new
|
||||
// turn starts. Depletion (credits.depleted) and other notices stay — they're
|
||||
// explicitly sticky until the policy clears them.
|
||||
if (getUiState().notice?.key === 'credits.usage') {
|
||||
this.clearNotice('credits.usage')
|
||||
// "Flash and yield" notices clear when a new turn starts: a usage-band heads-up
|
||||
// (credits.usage, 50/75/90%) and the one-time "grant spent" transition
|
||||
// (credits.grant_spent) should show once, then get out of the way — not camp the
|
||||
// bar (e.g. "Grant spent · $990 top-up left" sitting there with plenty of top-up
|
||||
// left). Depletion (credits.depleted) and other notices stay — they're explicitly
|
||||
// sticky until the policy clears them. The Python `active` latch retains the key,
|
||||
// so a yielded notice won't re-fire on the next turn.
|
||||
const yieldingNoticeKey = getUiState().notice?.key
|
||||
if (yieldingNoticeKey === 'credits.usage' || yieldingNoticeKey === 'credits.grant_spent') {
|
||||
this.clearNotice(yieldingNoticeKey)
|
||||
}
|
||||
patchUiState({ busy: true })
|
||||
patchTurnState({ activity: [], outcome: '', subagents: [], toolTokens: 0, tools: [], turnTrail: [] })
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue