Skip to content

feat(config): make per-turn spend limit user-configurable#20

Merged
1bcMax merged 2 commits intomainfrom
feat/configurable-turn-spend-limit
Apr 28, 2026
Merged

feat(config): make per-turn spend limit user-configurable#20
1bcMax merged 2 commits intomainfrom
feat/configurable-turn-spend-limit

Conversation

@KillerQueen-Z
Copy link
Copy Markdown
Collaborator

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:

⚠️ Turn spend limit reached ($0.269 > $0.25). Stopping to protect your wallet. Try again with a clearer prompt or a different model.

…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:

value behavior
unset / non-numeric keep $0.25 default (current behavior)
`0` or negative cap removed (`Infinity`), warning never fires
positive number that value as the ceiling

The existing warning text already prints the active value, so users always see exactly what limit they hit.

Files

  • `src/commands/config.ts` — add `max-turn-spend-usd` to `VALID_KEYS` + `AppConfig` with a doc comment
  • `src/agent/loop.ts` — replace the hard-coded `const MAX_TURN_SPEND_USD = 0.25` with a config read at turn start

```
src/agent/loop.ts | 14 +++++++++++++-
src/commands/config.ts | 8 ++++++++
2 files changed, 21 insertions(+), 1 deletion(-)
```

Out of scope

  • No change to the breaker logic itself, warning text, or any other spend-tracking behavior.
  • No new CLI subcommand — `config set` already covers this.
  • No new env var — config file is the right place for per-user overrides.

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.

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.
@1bcMax 1bcMax merged commit 562e1f0 into main Apr 28, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant