unify limit per day #98

Open
opened 2026-06-09 08:37:35 +00:00 by salmaelsoly · 3 comments
Member

unify limit per day to be budget or step limit or iteration limit

unify limit per day to be budget or step limit or iteration limit
Author
Member

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)

  • Runtime config holds two iteration ceilings, defaulted in crates/hero_shrimp_runtime/src/config/agent_build.rs:25-26:
    agent_max_iterations: helpers::u32_or(lookup, "SHRIMP_MAX_ITERATIONS", 32),
    agent_hard_max_iterations: helpers::u32_or(lookup, "SHRIMP_MAX_ITERATIONS_HARD", 400),
    
    Declared in crates/hero_shrimp_runtime/src/config/mod.rs:97-98, validated > 0 and hard >= soft at config/mod.rs:440-451.
  • YAML source fields: crates/hero_shrimp_runtime/src/config_yaml/schema.rs:587-588 (AgentConfig.max_iterations, hard_max_iterations), piped to env at config/yaml.rs:45-46.
  • Resolved per run in crates/hero_shrimp_engine/src/agent_core/agent/loop_support.rs:221-227 (resolve_iteration_budget) and consumed at loop_setup.rs:237-249, feeding AgentBudget::new(max_iters, max_duration).
  • AgentBudget / IterationBudget (crates/hero_shrimp_engine/src/boundaries/iteration_budget.rs) returns Exhaustion::IterLimit when iterations run out. The only place the loop is stopped by iteration count is tick_iteration in crates/hero_shrimp_engine/src/agent_core/agent/iteration_shell.rs:81-173 (the _ => arm returns IterAction::Break).
  • max_total() / remaining() are also read advisorily (not for termination) by goal_evaluation.rs:50, no_tool_calls.rs:96, loop_finalize.rs:50, claims_nudge.rs:80, llm_failover.rs:36, plus trace lines.
  • Per-run override sources that also cap iterations: autonomy_dispatch.rs:101-107, chat_turn.rs:130-135, and parse_max_iterations_param(...) in job/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-16 maps budget.daily_usdSHRIMP_LLM_DAILY_USD_CAPconfig.llm_daily_usd_cap (config/mod.rs:165, 405).
  • Every completion call pre-flight-checks the running total in crates/hero_shrimp_runtime/src/llm/completion/mod.rs:123:
    crate::llm::spending::check_cap_or_err(config.llm_daily_usd_cap, config.llm_monthly_usd_cap)?;
    
    check_cap_or_err (spending.rs:313-368) errors once m.usd_today >= cap. Each call's cost is accumulated by spending::record(...). So once spend reaches the budget, the next LLM call returns Err, which ends the run. This is the existing mid-run budget stop — budget already limits execution, not just at job start.
  • Pre-flight gate: enforce_budget_gate in crates/hero_shrimp_server/src/rpc/methods/job/start.rs:593-..., currently reads only budget.daily_usd.
  • Duplicate/unenforced per-job USD fields: 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

  1. Disable iteration limiting without removing the machinery. When iteration limiting is disabled (the new default), build AgentBudget with an effectively-unbounded ceiling (sentinel i64::MAX / 4) so exhausted() never returns IterLimit. AgentBudget/IterationBudget stay in place; the ~8 advisory readers keep working (a huge remaining() just means "not iteration-bound"). The sentinel is i64::MAX / 4 (not i64::MAX) so used()/refund() arithmetic (iteration_budget.rs:48,61) cannot overflow; any max_total() as u32 read site is clamped/saturated as needed.

  2. Budget is the single limiter — already mid-run. No new mid-run stop is invented: completion/mod.rs:123 already terminates the run when spend reaches budget.daily_usd. Keep daily_usd → per-call-cap wiring as the canonical mechanism.

  3. 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 to llm_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_gate at job.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.

  4. Consolidate the three per-job USD fields. budget.daily_usd is the one canonical, enforced budget field. BudgetConfig.per_job_usd, BudgetConfig.per_job_max_calls, and AutonomyConfig.job_budget_usd are documented as deprecated/no-op, kept parseable for backward compatibility (so existing shrimp.yml files still load), but carry no enforcement. No new call-count limiting is added (call-count is exactly the non-budget limiter being removed).


Requirements

  • The agent loop MUST NOT terminate due to iteration/step count.
  • A configured spend budget (budget.daily_usd) MUST terminate a run mid-execution once reached (already true via completion/mod.rs:123).
  • A budget MUST be configured: a run with no/zero budget is refused with a clear error — no configuration can produce an unbounded loop.
  • One canonical budget field; duplicate per-job USD / call-count fields deprecated and non-load-bearing, but still parseable.
  • No behavioural change to max_tool_calls_per_iteration (within-turn only).
  • Existing IterationBudget/AgentBudget arithmetic tests remain valid.

Files to Modify/Create

  • crates/hero_shrimp_runtime/src/config_yaml/schema.rs — add AgentConfig.iteration_limit_enabled: Option<bool> (+ merge); update doc comments on per_job_usd, per_job_max_calls, job_budget_usd to deprecated/no-op pointing to budget.daily_usd.
  • crates/hero_shrimp_runtime/src/config/yaml.rs — add YAML→env mapping for the new flag; confirm SHRIMP_LLM_DAILY_USD_CAPbudget.daily_usd stays.
  • crates/hero_shrimp_runtime/src/config/agent_build.rs — read the new flag (default: limiting disabled).
  • crates/hero_shrimp_runtime/src/config/mod.rs — add agent_iteration_limit_enabled: bool; relax the agent_max_iterations > 0 validation so disabling is legal; add the mandatory-budget validation (error when limiting disabled AND no llm_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; ignore iteration_budget_override in 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.rsenforce_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 — document budget.daily_usd as the single required limiter; mark deprecated fields; document agent.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.

  • Add AgentConfig.iteration_limit_enabled: Option<bool> + merge entry; map to env SHRIMP_ITERATION_LIMIT_ENABLED; read into Config.agent_iteration_limit_enabled with default false (limiting disabled).
  • Adjust validation at config/mod.rs:440-451 so agent_max_iterations > 0 / hard >= soft is 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.

  • In config validation: when iteration limiting is disabled and no spend budget is set (llm_daily_usd_cap is None/<= 0), return a clear configuration error instructing the operator to set budget.daily_usd.
  • In enforce_budget_gate (job/start.rs:593): refuse job start with a structured forbidden/invalid error 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.

  • Add const UNBOUNDED_ITERATIONS: i64 = i64::MAX / 4;. In loop_setup.rs:237-249, when limiting is disabled, set max_iters to the sentinel instead of resolve_iteration_budget(...), and ignore iteration_budget_override so 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.

  • Update doc comments on per_job_usd, per_job_max_calls (schema.rs:142-149) and AutonomyConfig.job_budget_usd (schema.rs:650-651) to deprecated/no-op, pointing to budget.daily_usd. Keep fields parseable. Update default.yml to document budget.daily_usd as the single required limiter, mark deprecated fields, and document agent.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-bearing max_total() as u32 exists).

  • Verify used()/refund() do not overflow with the sentinel. Clamp/saturate any max_total() as u32 read site that would misbehave with a huge value. Add a doc note on AgentBudget.
    Dependencies: Step 3.

Step 6 — Tests

Files: tests in crates/hero_shrimp_runtime (config + spending) and crates/hero_shrimp_engine (loop/budget).

  • (a) Config: a disabled-iteration-limit config with no budget is rejected; with a budget it is accepted. (b) check_cap_or_err(Some(cap), None) errors once recorded spend >= cap (documenting the run-terminating budget stop). (c) With limiting disabled, AgentBudget is built with the sentinel and exhausted() returns Alive for ordinary turn counts. (d) Existing iteration_budget.rs arithmetic tests still pass.
    Dependencies: Steps 2, 3.

Parallelism: Step 4 is independent. Steps 1 → {2, 3} → {5, 6}.


Acceptance Criteria

  • With default config, the agent loop never returns Exhaustion::IterLimit; runs are not stopped by iteration count.
  • A configured budget.daily_usd terminates an in-flight run once cumulative spend reaches it.
  • A run with no/zero budget is refused with a clear error at startup validation and at job.start — no configuration yields an unbounded loop.
  • budget.daily_usd is the single documented/enforced budget field; per_job_usd, per_job_max_calls, and autonomy.job_budget_usd are documented as deprecated/no-op and remain parseable.
  • max_tool_calls_per_iteration behaviour is unchanged.
  • Existing iteration_budget.rs arithmetic tests pass; new tests for the mandatory-budget rejection and the disabled-iteration behaviour pass.
  • Config validation no longer rejects a disabled-iteration-limit configuration (when a budget is present).

Notes

  • No new mid-run budget machinery is required — budget already limits execution per-call at 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.
  • Sentinel sizing: i64::MAX / 4 avoids overflow in used()/refund(). Confirm each max_total() as u32 site tolerates saturation; clamp where needed (Step 5).
  • Wall-clock duration is retained as an optional secondary stop but is not required given the mandatory budget.
  • Grace call (agent_grace_call_enabled) effectively never fires once the ceiling is unbounded; acceptable for this change.
  • Eval harness sets max_iterations per scenario; eval can opt back into iteration limiting via agent.iteration_limit_enabled = true so deterministic eval runs are unaffected.
  • Interpretation: there is no field literally named "limit per day"; the actionable reading (confirmed with the maintainer) is to disable the step/iteration limiter and make the spend budget the single limiting mechanism, with a budget required.
## 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) - Runtime config holds two iteration ceilings, defaulted in `crates/hero_shrimp_runtime/src/config/agent_build.rs:25-26`: ```rust agent_max_iterations: helpers::u32_or(lookup, "SHRIMP_MAX_ITERATIONS", 32), agent_hard_max_iterations: helpers::u32_or(lookup, "SHRIMP_MAX_ITERATIONS_HARD", 400), ``` Declared in `crates/hero_shrimp_runtime/src/config/mod.rs:97-98`, validated `> 0` and `hard >= soft` at `config/mod.rs:440-451`. - YAML source fields: `crates/hero_shrimp_runtime/src/config_yaml/schema.rs:587-588` (`AgentConfig.max_iterations`, `hard_max_iterations`), piped to env at `config/yaml.rs:45-46`. - Resolved per run in `crates/hero_shrimp_engine/src/agent_core/agent/loop_support.rs:221-227` (`resolve_iteration_budget`) and consumed at `loop_setup.rs:237-249`, feeding `AgentBudget::new(max_iters, max_duration)`. - `AgentBudget` / `IterationBudget` (`crates/hero_shrimp_engine/src/boundaries/iteration_budget.rs`) returns `Exhaustion::IterLimit` when iterations run out. The only place the loop is stopped by iteration count is `tick_iteration` in `crates/hero_shrimp_engine/src/agent_core/agent/iteration_shell.rs:81-173` (the `_ =>` arm returns `IterAction::Break`). - `max_total()` / `remaining()` are also read advisorily (not for termination) by `goal_evaluation.rs:50`, `no_tool_calls.rs:96`, `loop_finalize.rs:50`, `claims_nudge.rs:80`, `llm_failover.rs:36`, plus trace lines. - Per-run override sources that also cap iterations: `autonomy_dispatch.rs:101-107`, `chat_turn.rs:130-135`, and `parse_max_iterations_param(...)` in `job/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-16` maps `budget.daily_usd` → `SHRIMP_LLM_DAILY_USD_CAP` → `config.llm_daily_usd_cap` (`config/mod.rs:165, 405`). - Every completion call pre-flight-checks the running total in `crates/hero_shrimp_runtime/src/llm/completion/mod.rs:123`: ```rust crate::llm::spending::check_cap_or_err(config.llm_daily_usd_cap, config.llm_monthly_usd_cap)?; ``` `check_cap_or_err` (`spending.rs:313-368`) errors once `m.usd_today >= cap`. Each call's cost is accumulated by `spending::record(...)`. So once spend reaches the budget, the next LLM call returns `Err`, which ends the run. **This is the existing mid-run budget stop — budget already limits execution, not just at job start.** - Pre-flight gate: `enforce_budget_gate` in `crates/hero_shrimp_server/src/rpc/methods/job/start.rs:593-...`, currently reads only `budget.daily_usd`. - Duplicate/unenforced per-job USD fields: `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 1. **Disable iteration limiting without removing the machinery.** When iteration limiting is disabled (the new default), build `AgentBudget` with an effectively-unbounded ceiling (sentinel `i64::MAX / 4`) so `exhausted()` never returns `IterLimit`. `AgentBudget`/`IterationBudget` stay in place; the ~8 advisory readers keep working (a huge `remaining()` just means "not iteration-bound"). The sentinel is `i64::MAX / 4` (not `i64::MAX`) so `used()`/`refund()` arithmetic (`iteration_budget.rs:48,61`) cannot overflow; any `max_total() as u32` read site is clamped/saturated as needed. 2. **Budget is the single limiter — already mid-run.** No new mid-run stop is invented: `completion/mod.rs:123` already terminates the run when spend reaches `budget.daily_usd`. Keep `daily_usd` → per-call-cap wiring as the canonical mechanism. 3. **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 to `llm_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_gate` at `job.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. 4. **Consolidate the three per-job USD fields.** `budget.daily_usd` is the one canonical, enforced budget field. `BudgetConfig.per_job_usd`, `BudgetConfig.per_job_max_calls`, and `AutonomyConfig.job_budget_usd` are documented as deprecated/no-op, kept parseable for backward compatibility (so existing `shrimp.yml` files still load), but carry no enforcement. No new call-count limiting is added (call-count is exactly the non-budget limiter being removed). --- ### Requirements - The agent loop MUST NOT terminate due to iteration/step count. - A configured spend budget (`budget.daily_usd`) MUST terminate a run mid-execution once reached (already true via `completion/mod.rs:123`). - A budget MUST be configured: a run with no/zero budget is refused with a clear error — no configuration can produce an unbounded loop. - One canonical budget field; duplicate per-job USD / call-count fields deprecated and non-load-bearing, but still parseable. - No behavioural change to `max_tool_calls_per_iteration` (within-turn only). - Existing `IterationBudget`/`AgentBudget` arithmetic tests remain valid. --- ### Files to Modify/Create - `crates/hero_shrimp_runtime/src/config_yaml/schema.rs` — add `AgentConfig.iteration_limit_enabled: Option<bool>` (+ merge); update doc comments on `per_job_usd`, `per_job_max_calls`, `job_budget_usd` to deprecated/no-op pointing to `budget.daily_usd`. - `crates/hero_shrimp_runtime/src/config/yaml.rs` — add YAML→env mapping for the new flag; confirm `SHRIMP_LLM_DAILY_USD_CAP` ← `budget.daily_usd` stays. - `crates/hero_shrimp_runtime/src/config/agent_build.rs` — read the new flag (default: limiting disabled). - `crates/hero_shrimp_runtime/src/config/mod.rs` — add `agent_iteration_limit_enabled: bool`; relax the `agent_max_iterations > 0` validation so disabling is legal; add the **mandatory-budget** validation (error when limiting disabled AND no `llm_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; ignore `iteration_budget_override` in 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` — document `budget.daily_usd` as the single required limiter; mark deprecated fields; document `agent.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`. - Add `AgentConfig.iteration_limit_enabled: Option<bool>` + merge entry; map to env `SHRIMP_ITERATION_LIMIT_ENABLED`; read into `Config.agent_iteration_limit_enabled` with **default `false`** (limiting disabled). - Adjust validation at `config/mod.rs:440-451` so `agent_max_iterations > 0` / `hard >= soft` is 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`. - In config validation: when iteration limiting is disabled and no spend budget is set (`llm_daily_usd_cap` is `None`/`<= 0`), return a clear configuration error instructing the operator to set `budget.daily_usd`. - In `enforce_budget_gate` (`job/start.rs:593`): refuse job start with a structured `forbidden`/`invalid` error 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`. - Add `const UNBOUNDED_ITERATIONS: i64 = i64::MAX / 4;`. In `loop_setup.rs:237-249`, when limiting is disabled, set `max_iters` to the sentinel instead of `resolve_iteration_budget(...)`, and ignore `iteration_budget_override` so 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`. - Update doc comments on `per_job_usd`, `per_job_max_calls` (`schema.rs:142-149`) and `AutonomyConfig.job_budget_usd` (`schema.rs:650-651`) to deprecated/no-op, pointing to `budget.daily_usd`. Keep fields parseable. Update `default.yml` to document `budget.daily_usd` as the single required limiter, mark deprecated fields, and document `agent.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-bearing `max_total() as u32` exists). - Verify `used()`/`refund()` do not overflow with the sentinel. Clamp/saturate any `max_total() as u32` read site that would misbehave with a huge value. Add a doc note on `AgentBudget`. Dependencies: Step 3. #### Step 6 — Tests Files: tests in `crates/hero_shrimp_runtime` (config + spending) and `crates/hero_shrimp_engine` (loop/budget). - (a) Config: a disabled-iteration-limit config with no budget is rejected; with a budget it is accepted. (b) `check_cap_or_err(Some(cap), None)` errors once recorded spend `>= cap` (documenting the run-terminating budget stop). (c) With limiting disabled, `AgentBudget` is built with the sentinel and `exhausted()` returns `Alive` for ordinary turn counts. (d) Existing `iteration_budget.rs` arithmetic tests still pass. Dependencies: Steps 2, 3. **Parallelism:** Step 4 is independent. Steps 1 → {2, 3} → {5, 6}. --- ### Acceptance Criteria - [ ] With default config, the agent loop never returns `Exhaustion::IterLimit`; runs are not stopped by iteration count. - [ ] A configured `budget.daily_usd` terminates an in-flight run once cumulative spend reaches it. - [ ] A run with no/zero budget is refused with a clear error at startup validation and at `job.start` — no configuration yields an unbounded loop. - [ ] `budget.daily_usd` is the single documented/enforced budget field; `per_job_usd`, `per_job_max_calls`, and `autonomy.job_budget_usd` are documented as deprecated/no-op and remain parseable. - [ ] `max_tool_calls_per_iteration` behaviour is unchanged. - [ ] Existing `iteration_budget.rs` arithmetic tests pass; new tests for the mandatory-budget rejection and the disabled-iteration behaviour pass. - [ ] Config validation no longer rejects a disabled-iteration-limit configuration (when a budget is present). --- ### Notes - **No new mid-run budget machinery is required** — budget already limits execution per-call at `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. - **Sentinel sizing:** `i64::MAX / 4` avoids overflow in `used()`/`refund()`. Confirm each `max_total() as u32` site tolerates saturation; clamp where needed (Step 5). - **Wall-clock duration** is retained as an optional secondary stop but is not required given the mandatory budget. - **Grace call** (`agent_grace_call_enabled`) effectively never fires once the ceiling is unbounded; acceptable for this change. - **Eval harness** sets `max_iterations` per scenario; eval can opt back into iteration limiting via `agent.iteration_limit_enabled = true` so deterministic eval runs are unaffected. - **Interpretation:** there is no field literally named "limit per day"; the actionable reading (confirmed with the maintainer) is to disable the step/iteration limiter and make the spend budget the single limiting mechanism, with a budget required.
Author
Member

Test Results

Validated the changed crates (hero_shrimp_runtime, hero_shrimp_engine, hero_shrimp_server).

  • Build: cargo check clean for runtime, engine, and the server library.
  • Lint: cargo clippy -- -D warnings clean for all three.
  • Unit tests:
    • hero_shrimp_runtime: 559 passed, 0 failed
    • hero_shrimp_engine: 1665 passed, 0 failed (includes 2 new tests covering the unbounded iteration ceiling)

Note: a full-workspace build is currently blocked by pre-existing upstream dependency drift unrelated to this change (the hero_rpc development branch no longer resolves hero_rpc_openrpc, used only by hero_shrimp_sdk; and herolib_core::base no longer exports the helpers used by hero_shrimp_server/src/main.rs). The crates touched by this change compile, lint, and test cleanly.

## Test Results Validated the changed crates (hero_shrimp_runtime, hero_shrimp_engine, hero_shrimp_server). - Build: `cargo check` clean for runtime, engine, and the server library. - Lint: `cargo clippy -- -D warnings` clean for all three. - Unit tests: - hero_shrimp_runtime: 559 passed, 0 failed - hero_shrimp_engine: 1665 passed, 0 failed (includes 2 new tests covering the unbounded iteration ceiling) Note: a full-workspace build is currently blocked by pre-existing upstream dependency drift unrelated to this change (the `hero_rpc` development branch no longer resolves `hero_rpc_openrpc`, used only by `hero_shrimp_sdk`; and `herolib_core::base` no longer exports the helpers used by `hero_shrimp_server/src/main.rs`). The crates touched by this change compile, lint, and test cleanly.
Author
Member

Pull request opened: #101

This PR implements the changes discussed in this issue.

Pull request opened: https://forge.ourworld.tf/lhumina_code/hero_shrimp/pulls/101 This PR implements the changes discussed in this issue.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_shrimp#98
No description provided.