feat(goals): opt-in token budget for /goal (input/output caps) - #90285
feat(goals): opt-in token budget for /goal (input/output caps)#90285HermesZum wants to merge 1 commit into
Conversation
Clarification: how this relates to the turn-budget work (#37263)This PR is not a re-do or conflict with #37263 — it adds a different axis of the same surface:
The two are distinguished by argument shape, not by a separate keyword, so there is no CLI-parser collision:
Both are opt-in and additive; a goal with neither set behaves exactly as today. The token budget is enforced off the existing If maintainers would prefer a single unified syntax (e.g. |
Status update (2026-08-20): rebased onto current
|
Add an optional input/output token cap to the existing /goal goal/gate machinery (prime-agent port). Budget is measured as the delta in recorded session tokens (session_model_usage) since the goal (re)started, so it applies to this goal's spend rather than lifetime totals. Enforcement pauses the goal with a dedicated 'token_budget_exhausted' verdict, parallel to the existing turn-budget exhaustion path. Off by default (Nones) → fully backwards-compatible; old state_meta rows load unchanged. - hermes_cli/goals.py: GoalState.max_input_tokens/max_output_tokens + baselines; _current_session_tokens() reads session_model_usage; set()/ resume() capture baseline; set_budget()/clear_budget(); evaluate_after_turn enforces; status_line surfaces budget. - hermes_cli/cli_commands_mixin.py: '/goal budget in:<n> out:<n>' / 'off'. - tests/hermes_cli/test_goals_token_budget.py: 8 tests (round-trip, enforcement, set/clear, resume re-baseline, status line) — all pass. Regression: 67 goals/refine/background_review tests pass.
610531c to
944e952
Compare
|
Closing: features moved to a private plugin (HermesZum/prime-agent-features). This PR is withdrawn. |
Summary
Adds an opt-in input/output token budget to the existing durable
/goalmachinery (hermes_cli/goals.py), enforced alongside the existingmax_turnsbackstop. A long-running goal currently has only a turn cap; this adds a token cap so a goal cannot burn unbounded tokens. Ports prime-agent's "durable/goalwith token budget" by extending the existinggoals.pyprimitive — no architecture fork, no prompt-cache or message-role invariant break.Closes #90286.
Changes
hermes_cli/goals.py:GoalStategainsmax_input_tokens/max_output_tokens(JSON round-trip via existingstate_meta) + per-session baselines captured inset()/resume();set_budget()/clear_budget();evaluate_after_turnenforces the delta since goal start read from the existingsession_model_usagetable (notaux_accounting, which would double-count main-loop usage);status_linesurfaces the budget.hermes_cli/cli_commands_mixin.py:/goal budget in:<n> out:<n>and/goal budget off.tests/hermes_cli/test_goals_token_budget.py(new, 8 tests): round-trip, enforcement pause, set/clear, resume re-baseline, status line.Design notes
max_input_tokens/max_output_tokensare unchanged.session_model_usagerows (main-loop, per-session) — reused, not a new table, consistent with howgoals.pyalready persists viastate_meta.max_turns), so behavior on exhaustion is consistent.input_tokens + output_tokens(reasoning/cache token nuance excluded).Relationship to existing work (Step-0 duplicate search, see #90286)
/goal budget <N>for turns; feat(goals): unbounded turn-budget sentinel + judge kill-switch #69308 unbounded turn sentinel). No existing effort adds a token budget — this is complementary, not overlapping.Test plan
tests/hermes_cli/test_goals_token_budget.py: 8 tests (round-trip, enforcement, set/clear, resume re-baseline, status line).test_goals.py(36) green — no regressions in touched modules.py_compileclean ongoals.py+cli_commands_mixin.py.Invariants preserved
GoalState; no schema migration.Notes / asks
/goal budgetsurface covering turns + tokens vs. separate token flags.