feat(config): make per-turn spend limit user-configurable#20
Merged
Conversation
The hard \$0.25 per-turn spend ceiling in loop.ts has been hard-coded since it was added. It's a safe default for typical chat, but it routinely fires for legitimate workloads where a single user prompt triggers expensive paid tools (image-to-image with gpt-image-2, multi-step VideoGen, large WebFetch+research turns), even though the user is fully aware they're spending more. When that happens the user gets:⚠️ Turn spend limit reached (\$0.269 > \$0.25). Stopping to protect your wallet. Try again with a clearer prompt or a different model. …and there's no way out short of editing the source. This change introduces a new config key \`max-turn-spend-usd\` so the ceiling can be raised (or removed) per-user without forking: \`\`\`bash franklin config set max-turn-spend-usd 1.0 # bump to \$1 franklin config set max-turn-spend-usd 0 # disable entirely franklin config unset max-turn-spend-usd # back to default \$0.25 \`\`\` Behavior: - Unset / non-numeric → keeps the original \$0.25 default - 0 or negative → cap removed (Infinity), warning never fires - Positive number → that ceiling The existing warning text in the loop already shows the active value, so users always see exactly what their limit is. Scope deliberately small — config schema + one read at turn start. No change to the breaker logic, the warning message, or any other spend-tracking behavior.
KillerQueen-Z
added a commit
that referenced
this pull request
Apr 28, 2026
…timeout UX - New mascot artwork on the empty state: a bigger AI+coin themed Franklin pixel-art portrait. The PNG ships with a flood-filled alpha channel so the mascot composites directly onto whichever theme background sits behind the panel — no rounded-rectangle frame, no mix-blend-mode hack. Original PNG (with the dark frame) also kept on disk as franklin-mascot.png for record / fallback. - Settings popover gains a "Per-turn spend cap (USD)" field. Empty keeps the existing $0.25 default; "0" disables the cap entirely; any positive number sets it. Local mirror of core PR #20. Core (cherry-picks of in-flight PRs) - src/tools/imagegen.ts: image-to-image gets a 180s timeout (was shared 60s with text-to-image — gpt-image-2 edits on a few-MB reference image consistently hit AbortError before completion). Mirror of PR #19. - src/agent/loop.ts + src/commands/config.ts: MAX_TURN_SPEND_USD is no longer hard-coded; reads max-turn-spend-usd from config with fallback to $0.25. Mirror of PR #20. Bumps vscode-extension to 0.4.5; updates README changelog.
…disable Previous code branched typos (NaN) into Infinity, silently removing the wallet guard. A circuit breaker should fail safe — only an explicit '0' or negative value opts out; anything unparseable falls back to the $0.25 default.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The hard $0.25 per-turn spend ceiling in `src/agent/loop.ts` has been hard-coded since it was added. It's a safe default for typical chat, but it routinely fires for legitimate workloads where a single user prompt triggers expensive paid tools (image-to-image with gpt-image-2, multi-step VideoGen, large WebFetch+research turns) — even though the user is fully aware they're spending more than $0.25 on the request.
When the limit hits, the user sees:
…and the only way out is editing the source.
Changes
New config key `max-turn-spend-usd` read once per turn at the top of `interactiveSession`:
```bash
franklin config set max-turn-spend-usd 1.0 # bump to $1
franklin config set max-turn-spend-usd 0 # disable entirely
franklin config unset max-turn-spend-usd # back to default $0.25
```
Resolution:
The existing warning text already prints the active value, so users always see exactly what limit they hit.
Files
```
src/agent/loop.ts | 14 +++++++++++++-
src/commands/config.ts | 8 ++++++++
2 files changed, 21 insertions(+), 1 deletion(-)
```
Out of scope
Test plan
```bash
Default — limit at $0.25
franklin --prompt ""
→⚠️ Turn spend limit reached ($0.32 > $0.25). Stopping…
Raise the cap
franklin config set max-turn-spend-usd 2.0
franklin --prompt ""
→ completes; runs to whatever budget
Disable entirely
franklin config set max-turn-spend-usd 0
→ no warning, agent runs to natural completion
Reset
franklin config unset max-turn-spend-usd
→ back to $0.25 default
```
Related
Comes from a real-world hit on PR #19's image-to-image flow — a successful gpt-image-2 edit ($0.06) + Sonnet planning + a couple of retries can land just over $0.25 on a single prompt the user definitely intended to send. With #19 merged, image-to-image will succeed more often, and this PR makes sure success doesn't get cut off mid-stream by an over-conservative default.