Skip to content

feat(agentloop): per-turn thinking/token budget enforcement (#375) - #406

Closed
Delqhi wants to merge 1 commit into
mainfrom
feat/per-turn-budget
Closed

feat(agentloop): per-turn thinking/token budget enforcement (#375)#406
Delqhi wants to merge 1 commit into
mainfrom
feat/per-turn-budget

Conversation

@Delqhi

@Delqhi Delqhi commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Per-turn budget enforcement with hooks.BudgetExceeded event. M3: budget-exceeded never bypasses verify gate.

)

Loop gains a per-turn budget tracker (perTurnBudget *PerTurnBudget)
that records thinking + total tokens for every single LLM turn and
returns ErrPerTurnBudgetExceeded when a non-zero cap is breached.

The charge happens AFTER the provider response, then the loop:
  1. fires hooks.BudgetExceeded with turn + caps + used so dashboards
     can render the precise per-trip breach
  2. sets verifiedOnly = true so subsequent per-run caps
     (MaxTokens / ThinkingBudgetPerRequest) are skipped for the rest
     of this turn (issue #375)
  3. returns the per-turn error to the caller so the post-mortem
     surfaces the cap as the failure cause

The verify-gate (Gate.Run) still runs on the over-cap response because
the response is appended to msgs before the error return (mandate M3:
budget must NEVER bypass verify).

New constants / config keys:
  hooks.BudgetExceeded                              = "budget.exceeded"
  SinCodeConfig.AgentLoopPerTurnBudget              (agentloop.per_turn_budget)
  SinCodeConfig.AgentLoopPerTurnThinkingBudget      (agentloop.per_turn_thinking_budget)
  loopbuilder.Config.PerTurnBudget
  loopbuilder.Config.PerTurnThinkingBudget

Wired end-to-end through loopbuilder/builder.go: cfg zeros are filled
from the merged SinCodeConfig exactly like the legacy
ThinkingBudgetPerRequest. Loop.Run() lazy-constructs the tracker only
when at least one per-turn cap is non-zero, so the no-cap path stays
zero-cost (mandate M7 race-clean check).

PerTurnBudget (in budget.go alongside the existing Budget struct):
  - PerTurnBudget.Reset()                  - zero per-turn, keep lifetime
  - PerTurnBudget.Charge(thinking, total)  - always increments first
  - PerTurnBudget.PreFlight()              - cut off BEFORE sending
  - PerTurnBudget.IsEnforced()             - cheap guard for lazy paths
  - nil-safe (every public method survives a nil receiver)

Tests (added to budget_test.go alongside existing Budget tests):
  - 8 unit tests on PerTurnBudget
  - 3 Loop.Run integration tests
  - All pass under -race -count=1 (mandate M7)
  - Full agentloop suite green (7.4s)

Verified clean: go build ./... ok; go test ./... ok; race detector clean.
@Delqhi Delqhi added the enhancement New feature or request label Jun 18, 2026
@vercel

vercel Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
sin-code Ready Ready Preview, Comment, Open in v0 Jun 18, 2026 6:13pm

@github-actions

Copy link
Copy Markdown

🏆 CEO Audit — A+ (100.0/100)

Metric Value
Grade A+
Score 100.0/100
Critical findings 0
High findings 0
Profile QUICK
Min grade gate B

📥 Download full report (Markdown)
📊 Download SARIF (for Code Scanning)

Run ~/.config/opencode/skills/ceo-audit/scripts/audit.sh . --profile=QUICK locally to reproduce.

@github-actions

Copy link
Copy Markdown

🏆 CEO Audit — A+ (100.0/100)

Metric Value
Grade A+
Score 100.0/100
Critical findings 0
High findings 0
Medium findings 0
Profile QUICK
Min grade gate B

📥 Download full report (Markdown)

Run ID: 27779950432 · Commit: ${github.sha}

Run ~/.config/opencode/skills/ceo-audit/scripts/audit.sh . --profile=QUICK locally to reproduce.

@Delqhi

Delqhi commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator Author

Closing as duplicate. Issue #375 (Per-turn budget enforcement) was already shipped by a parallel agent on main:

  • Already committed: cmd/sin-code/internal/agentloop/{budget.go,per_turn_budget.go}
  • This branch feat/per-turn-budget was created from an older snapshot of main; merging would create conflicts and risk deleting parallel agent work.
  • The shipped implementation lives on current main (see commits by parallel agents).

@Delqhi Delqhi closed this Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant