unify limit per day #98
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_shrimp#98
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
unify limit per day to be budget or step limit or iteration limit
Implementation Spec for Issue #98 — unify limit per day
Objective
Make the spend budget the single mechanism that limits a job/agent run. Disable the agent step / iteration ceiling so it no longer terminates execution. A run ends when it finishes naturally or when the configured spend budget is reached — never because an iteration counter ran out. To guarantee every run is bounded, a budget becomes mandatory: a run is refused if no budget is configured. The three overlapping per-job USD fields are consolidated into one canonical budget field.
Current State
A. The iteration-limit path (to be disabled)
crates/hero_shrimp_runtime/src/config/agent_build.rs:25-26: Declared incrates/hero_shrimp_runtime/src/config/mod.rs:97-98, validated> 0andhard >= softatconfig/mod.rs:440-451.crates/hero_shrimp_runtime/src/config_yaml/schema.rs:587-588(AgentConfig.max_iterations,hard_max_iterations), piped to env atconfig/yaml.rs:45-46.crates/hero_shrimp_engine/src/agent_core/agent/loop_support.rs:221-227(resolve_iteration_budget) and consumed atloop_setup.rs:237-249, feedingAgentBudget::new(max_iters, max_duration).AgentBudget/IterationBudget(crates/hero_shrimp_engine/src/boundaries/iteration_budget.rs) returnsExhaustion::IterLimitwhen iterations run out. The only place the loop is stopped by iteration count istick_iterationincrates/hero_shrimp_engine/src/agent_core/agent/iteration_shell.rs:81-173(the_ =>arm returnsIterAction::Break).max_total()/remaining()are also read advisorily (not for termination) bygoal_evaluation.rs:50,no_tool_calls.rs:96,loop_finalize.rs:50,claims_nudge.rs:80,llm_failover.rs:36, plus trace lines.autonomy_dispatch.rs:101-107,chat_turn.rs:130-135, andparse_max_iterations_param(...)injob/start,session,eval.max_tool_calls_per_iteration(schema.rs:590) only bounds parallel tool calls within a turn — it does not terminate a run and is out of scope.B. The budget path (to become the sole limiter)
crates/hero_shrimp_runtime/src/config/yaml.rs:10-16mapsbudget.daily_usd→SHRIMP_LLM_DAILY_USD_CAP→config.llm_daily_usd_cap(config/mod.rs:165, 405).crates/hero_shrimp_runtime/src/llm/completion/mod.rs:123:check_cap_or_err(spending.rs:313-368) errors oncem.usd_today >= cap. Each call's cost is accumulated byspending::record(...). So once spend reaches the budget, the next LLM call returnsErr, which ends the run. This is the existing mid-run budget stop — budget already limits execution, not just at job start.enforce_budget_gateincrates/hero_shrimp_server/src/rpc/methods/job/start.rs:593-..., currently reads onlybudget.daily_usd.BudgetConfig.per_job_usd(schema.rs:142-143),BudgetConfig.per_job_max_calls(schema.rs:148-149),AutonomyConfig.job_budget_usd(schema.rs:650-651) — defined, none enforced.Design Decision
Disable iteration limiting without removing the machinery. When iteration limiting is disabled (the new default), build
AgentBudgetwith an effectively-unbounded ceiling (sentineli64::MAX / 4) soexhausted()never returnsIterLimit.AgentBudget/IterationBudgetstay in place; the ~8 advisory readers keep working (a hugeremaining()just means "not iteration-bound"). The sentinel isi64::MAX / 4(noti64::MAX) soused()/refund()arithmetic (iteration_budget.rs:48,61) cannot overflow; anymax_total() as u32read site is clamped/saturated as needed.Budget is the single limiter — already mid-run. No new mid-run stop is invented:
completion/mod.rs:123already terminates the run when spend reachesbudget.daily_usd. Keepdaily_usd→ per-call-cap wiring as the canonical mechanism.Budget is mandatory (safety guard — chosen approach). With iteration limiting disabled, a run with no spend budget would have no terminating ceiling. Therefore: refuse to run when no budget is configured.
budget.daily_usd(mapped tollm_daily_usd_cap) must be set and> 0; otherwise the run is rejected with a clear, structured error at the entry points (config validation at startup +enforce_budget_gateatjob.start). This makes budget the literal sole ceiling and guarantees no configuration can loop forever.max_duration/ wall-clock is left intact as an optional secondary stop but is not required.Consolidate the three per-job USD fields.
budget.daily_usdis the one canonical, enforced budget field.BudgetConfig.per_job_usd,BudgetConfig.per_job_max_calls, andAutonomyConfig.job_budget_usdare documented as deprecated/no-op, kept parseable for backward compatibility (so existingshrimp.ymlfiles still load), but carry no enforcement. No new call-count limiting is added (call-count is exactly the non-budget limiter being removed).Requirements
budget.daily_usd) MUST terminate a run mid-execution once reached (already true viacompletion/mod.rs:123).max_tool_calls_per_iteration(within-turn only).IterationBudget/AgentBudgetarithmetic tests remain valid.Files to Modify/Create
crates/hero_shrimp_runtime/src/config_yaml/schema.rs— addAgentConfig.iteration_limit_enabled: Option<bool>(+ merge); update doc comments onper_job_usd,per_job_max_calls,job_budget_usdto deprecated/no-op pointing tobudget.daily_usd.crates/hero_shrimp_runtime/src/config/yaml.rs— add YAML→env mapping for the new flag; confirmSHRIMP_LLM_DAILY_USD_CAP←budget.daily_usdstays.crates/hero_shrimp_runtime/src/config/agent_build.rs— read the new flag (default: limiting disabled).crates/hero_shrimp_runtime/src/config/mod.rs— addagent_iteration_limit_enabled: bool; relax theagent_max_iterations > 0validation so disabling is legal; add the mandatory-budget validation (error when limiting disabled AND nollm_daily_usd_cap/budget set).crates/hero_shrimp_engine/src/agent_core/agent/loop_setup.rs— at:237-249, when limiting disabled use the sentinel ceiling; ignoreiteration_budget_overridein that case.crates/hero_shrimp_engine/src/agent_core/agent/loop_support.rs— add a sibling resolver (or branch) returning the sentinel when limiting disabled; keep the existing fn for callers that still clamp.crates/hero_shrimp_server/src/rpc/methods/job/start.rs—enforce_budget_gate(:593): keep as pre-flight budget gate; add the mandatory-budget rejection (refuse when no budget configured). No call-count gate.crates/hero_shrimp_engine/src/boundaries/iteration_budget.rs— no logic change; doc note that a sentinel ceiling means "budget-governed / unbounded iterations"; verify no overflow with the sentinel.crates/hero_shrimp_runtime/config/default.yml— documentbudget.daily_usdas the single required limiter; mark deprecated fields; documentagent.iteration_limit_enabled.Implementation Plan
Step 1 — Add the "iteration limiting disabled" flag (config layer)
Files:
config_yaml/schema.rs,config/yaml.rs,config/agent_build.rs,config/mod.rs.AgentConfig.iteration_limit_enabled: Option<bool>+ merge entry; map to envSHRIMP_ITERATION_LIMIT_ENABLED; read intoConfig.agent_iteration_limit_enabledwith defaultfalse(limiting disabled).config/mod.rs:440-451soagent_max_iterations > 0/hard >= softis only enforced when the flag is enabled.Dependencies: none.
Step 2 — Mandatory-budget validation + pre-flight gate
Files:
config/mod.rs,crates/hero_shrimp_server/src/rpc/methods/job/start.rs.llm_daily_usd_capisNone/<= 0), return a clear configuration error instructing the operator to setbudget.daily_usd.enforce_budget_gate(job/start.rs:593): refuse job start with a structuredforbidden/invaliderror when no budget is configured (same message style as the existing daily-cap path). Respect the existing override env escape hatch where applicable.Dependencies: Step 1.
Step 3 — Sentinel ceiling resolver (disable iteration termination)
Files:
loop_support.rs,loop_setup.rs.const UNBOUNDED_ITERATIONS: i64 = i64::MAX / 4;. Inloop_setup.rs:237-249, when limiting is disabled, setmax_itersto the sentinel instead ofresolve_iteration_budget(...), and ignoreiteration_budget_overrideso the sentinel always wins.Dependencies: Step 1.
Step 4 — Consolidate budget fields (docs/deprecation)
Files:
config_yaml/schema.rs,crates/hero_shrimp_runtime/config/default.yml.per_job_usd,per_job_max_calls(schema.rs:142-149) andAutonomyConfig.job_budget_usd(schema.rs:650-651) to deprecated/no-op, pointing tobudget.daily_usd. Keep fields parseable. Updatedefault.ymlto documentbudget.daily_usdas the single required limiter, mark deprecated fields, and documentagent.iteration_limit_enabled.Dependencies: none (parallel-safe with Steps 1-3).
Step 5 — Overflow / advisory call-site safety
Files:
boundaries/iteration_budget.rs,no_tool_calls.rs,llm_failover.rs(only if a load-bearingmax_total() as u32exists).used()/refund()do not overflow with the sentinel. Clamp/saturate anymax_total() as u32read site that would misbehave with a huge value. Add a doc note onAgentBudget.Dependencies: Step 3.
Step 6 — Tests
Files: tests in
crates/hero_shrimp_runtime(config + spending) andcrates/hero_shrimp_engine(loop/budget).check_cap_or_err(Some(cap), None)errors once recorded spend>= cap(documenting the run-terminating budget stop). (c) With limiting disabled,AgentBudgetis built with the sentinel andexhausted()returnsAlivefor ordinary turn counts. (d) Existingiteration_budget.rsarithmetic tests still pass.Dependencies: Steps 2, 3.
Parallelism: Step 4 is independent. Steps 1 → {2, 3} → {5, 6}.
Acceptance Criteria
Exhaustion::IterLimit; runs are not stopped by iteration count.budget.daily_usdterminates an in-flight run once cumulative spend reaches it.job.start— no configuration yields an unbounded loop.budget.daily_usdis the single documented/enforced budget field;per_job_usd,per_job_max_calls, andautonomy.job_budget_usdare documented as deprecated/no-op and remain parseable.max_tool_calls_per_iterationbehaviour is unchanged.iteration_budget.rsarithmetic tests pass; new tests for the mandatory-budget rejection and the disabled-iteration behaviour pass.Notes
completion/mod.rs:123. The main risk is removing the iteration ceiling without leaving a run bounded; the mandatory-budget guard (Step 2) is the explicit safeguard and must not be omitted.i64::MAX / 4avoids overflow inused()/refund(). Confirm eachmax_total() as u32site tolerates saturation; clamp where needed (Step 5).agent_grace_call_enabled) effectively never fires once the ceiling is unbounded; acceptable for this change.max_iterationsper scenario; eval can opt back into iteration limiting viaagent.iteration_limit_enabled = trueso deterministic eval runs are unaffected.Test Results
Validated the changed crates (hero_shrimp_runtime, hero_shrimp_engine, hero_shrimp_server).
cargo checkclean for runtime, engine, and the server library.cargo clippy -- -D warningsclean for all three.Note: a full-workspace build is currently blocked by pre-existing upstream dependency drift unrelated to this change (the
hero_rpcdevelopment branch no longer resolveshero_rpc_openrpc, used only byhero_shrimp_sdk; andherolib_core::baseno longer exports the helpers used byhero_shrimp_server/src/main.rs). The crates touched by this change compile, lint, and test cleanly.Pull request opened: #101
This PR implements the changes discussed in this issue.