feat: --auto option, unlock auto/bypassPermissions permission modes via canonical claude-* model names#20
Closed
BenSheridanEdwards wants to merge 8 commits into
Conversation
…aude-* model names Claude Code disables `auto` and `bypassPermissions` modes when ANTHROPIC_DEFAULT_*_MODEL is not a `claude-*` value. Today deepclaude exports the resolved backend model names (e.g. `deepseek-v4-pro`) directly, which trips that gate — `Shift+Tab` reports "auto mode isn't available for this model". Fix: - Route the default `launch_claude` path through the local proxy (mirrors what `launch_remote` already does), so Claude Code talks to a Claude endpoint and the proxy translates model names on the wire via the existing MODEL_REMAP table. - Export canonical `claude-opus-4-7` / `claude-sonnet-4-6` / `claude-haiku-4-5-20251001` from `set_model_env` instead of the resolved backend names. - Extract a shared `start_proxy` helper used by both `launch_claude` and `launch_remote`. Symlink-resolve SCRIPT_DIR so deepclaude works when installed via `/usr/local/bin/deepclaude` symlink. - `start-proxy.js` legacy mode accepts an optional 3rd-positional `defaultMode`, so `state.mode` resolves to `deepseek` / `openrouter` / `fireworks` (not `_single` or `anthropic`) and `MODEL_REMAP[state.mode]` actually fires. - Add Fireworks entry to `MODEL_REMAP` to match deepseek/openrouter. After this change `deepclaude` shows `>> auto mode on (shift+tab to cycle)` at launch and Shift+Tab cycles default → auto → plan → bypassPermissions. Notes for reviewers: - This overlaps with draft PR aattaran#9 on the proxy-routing piece. PR aattaran#9 fixes cost-tracking but does not switch model env vars to canonical claude-* names, so PR aattaran#9 alone does not unlock auto mode. - This branch deliberately does NOT alter the existing thinking-strip policy from 70518b6. A separate experiment branch tests scoping that strip down for DeepSeek; results will inform a follow-up.
The launch banner advertised pro-tier models for slots the proxy actually routes to flash via MODEL_REMAP. Align RESOLVED_SONNET / RESOLVED_HAIKU / RESOLVED_SUBAGENT for ds, or, fw with the flash targets in proxy/model-proxy.js so the banner matches the wire. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The PR's EXIT trap (cleanup_proxy) was a silent no-op: start_proxy ran inside $() — a subshell — so PROXY_PID never reached the parent, leaving the node proxy orphaned on exit. Call start_proxy directly and have it set PROXY_PID/PROXY_PORT/PROXY_LOG as script globals. PROXY_LOG default also moves from /tmp/deepclaude-proxy.log to /tmp/deepclaude-proxy.\$\$.log so concurrent invocations don't truncate each other's logs (the file is opened with `: > "\$PROXY_LOG"` on every start). Resolved path is printed at launch so users can find it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…el_env If Claude Code starts requesting a model name that isn't in MODEL_REMAP[state.mode] (e.g. after Anthropic ships a model bump and the canonical-name list in deepclaude.sh drifts from the remap table), the proxy used to silently forward the unrecognized name and the backend would 404 with no diagnostic. Now warn loudly so the mismatch surfaces in the proxy log. Add an IMPORTANT note above set_model_env so future maintainers know the canonical names there must remain keys in every MODEL_REMAP backend block. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Now that the proxy logs to a file rather than the terminal, upstream errors and remap warnings (including the new unmapped-model warn from the previous commit) never reach the user mid-session. On non-zero, non-signal claude exit, dump the last 20 lines of \$PROXY_LOG to stderr so the cause is visible without having to hunt for the log path. Signal exits (>=128, e.g. 130 SIGINT) are suppressed so Ctrl+C stays silent. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The grep -E '^[0-9]+\$' port-extraction in start_proxy depends on start-proxy.js emitting its "[MODEL-PROXY] Listening on ..." banner before its final console.log(port). Document the invariant so a future tidy-up of the proxy startup logs doesn't quietly break it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The port-polling loop runs grep -E '^[0-9]+$' against \$PROXY_LOG to extract the bare-numeric port line emitted by start-proxy.js. On early iterations the proxy hasn't written its port yet, so grep finds zero matches and exits 1. With set -o pipefail, the grep|head pipeline propagates that failure; with set -e, the var=\$(...) assignment exits the script. Net effect: deepclaude died silently during proxy startup (no error message, just "Proxy stopped." from the EXIT trap) on any machine where the polling loop ran before the proxy emitted its port line — i.e. always, on a slow enough boot. Trail \`|| true\` on the pipeline so an empty match is OK; the loop's own \`[[ -z \"\$proxy_port\" ]]\` test handles "keep waiting" already. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Default mode now exports backend-native model names (deepseek-v4-pro etc.) so the TUI shows the real model — auto/bypassPermissions stay locked. --auto opts into canonical claude-* env vars to unlock auto mode; the launch banner prints a tip explaining the trade-off either way. Quiet the proxy's "no remap" warning for non-claude-* model names so it doesn't fire on every default-mode request (backend-native names are deliberate there). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Claude Code disables
autoandbypassPermissionsmodes when ANTHROPIC_DEFAULT_*_MODEL is not aclaude-*value. Today deepclaude exports the resolved backend model names (e.g.deepseek-v4-pro) directly, which trips that gate —Shift+Tabreports "auto mode isn't available for this model".This PR adds a
--autoopt-in that swaps the env vars to canonicalclaude-*names so the gate unlocks. Default behavior is unchanged: backend-native names in env vars and TUI, no auto/bypassPermissions. The bulk of the diff is proxy hardening that's needed regardless of which mode you launch in.Behavior
deepclaude(default, no--auto):deepseek-v4-pro,deepseek-v4-flash, etc.).deepclaude --auto:claude-opus-4-7/claude-sonnet-4-6/claude-haiku-4-5-20251001.MODEL_REMAPtranslates them back to backend names on the wire (#N model remap: claude-opus-4-7 → deepseek-v4-proin$PROXY_LOG).claude-opus-4-7(it lies — actual routing is still the configured backend).Caveat (auto mode only): Claude Code's in-session UI (status bar,
/model) shows the canonicalclaude-*name rather than the backend model — the trade-off for unlocking auto-mode. The launch banner still prints the resolved backend name, and the proxy logs every remap, so the actual routing is verifiable from outside the TUI.What's in the diff
Behavior gate:
--autoflag (default off).set_model_envbranches on it: auto = canonicalclaude-*names, default =$RESOLVED_OPUS/$RESOLVED_SONNET/$RESOLVED_HAIKU/$RESOLVED_SUBAGENT.print_auto_mode_tiphelper called by bothlaunch_claudeandlaunch_remoteso the trade-off is visible at launch in either mode.--helpdocuments--auto.Proxy / launch hardening (active in both modes):
launch_claudepath through the local proxy (mirrors whatlaunch_remotealready did), so requests go through the same code path regardless of mode.start-proxy.jslegacy mode accepts an optional 3rd-positionaldefaultMode, sostate.moderesolves todeepseek/openrouter/fireworks(not_singleoranthropic) andMODEL_REMAP[state.mode]actually fires. This also fixes a latent bug inlaunch_remote, which previously left the proxy in'anthropic'mode and forwarded requests toapi.anthropic.comregardless of the configured backend.MODEL_REMAPto match deepseek/openrouter.start_proxyhelper used by bothlaunch_claudeandlaunch_remote. Symlink-resolveSCRIPT_DIRso deepclaude works when installed via a/usr/local/bin/deepclaudesymlink.start_proxydirectly (not via$()) so thePROXY_PIDit sets actually reaches the parent shell — theEXITtrap was previously a silent no-op, leaving the node proxy orphaned on exit.start_proxynow setsPROXY_PID,PROXY_PORT, andPROXY_LOGas script globals.RESOLVED_HAIKU/RESOLVED_SONNET/RESOLVED_SUBAGENTwith whatMODEL_REMAPactually produces, so the launch banner matches the wire instead of advertising the pro model for slots the proxy routes to flash.$PROXY_LOGpath (/tmp/deepclaude-proxy.$$.log) so concurrent invocations don't truncate each other's logs. The resolved path is printed at launch.claudeexit, dump the tail of$PROXY_LOGto stderr so upstream proxy errors and remap warnings surface immediately. Clean exits and Ctrl+C stay silent.claude-*model name not inMODEL_REMAP[state.mode]— catches drift between the canonical-name list indeepclaude.shand the remap table the next time Anthropic ships a model bump. Backend-native names (default-mode wire format) are passed silently.grep -E '^[0-9]+$'depends on, plus a sync-required note aboveset_model_env.Notes for reviewers
claude-*names, so PR fix: route default launch through proxy (fixes cost tracking and auth override) #9 alone does not unlock auto mode.dsunder--auto, and that default mode shows backend names in the TUI with the expected tip in the launch banner. Static review only fororandfwpaths — keys not present in test environment.