Newer Claude models (Opus 4.7 and 4.8) no longer accept temperature, top_p, or top_k — sampling control was replaced by the effort parameter. If a client still sends one of those fields, the API rejects the whole request:
GitHub Copilot injects temperature and gives you no setting to turn it off, so any attempt to use Opus 4.8 through Copilot's bring-your-own-key (BYOK) path fails immediately.
This guide walks through a clean, general-purpose workaround: a tiny reverse proxy that removes those parameters before the request reaches Anthropic, plus the wiring to route Copilot through it. The same approach works for any client that injects deprecated sampling fields you can't disable.
How the fix works
We insert a small proxy between the client and Anthropic. It deletes the offending fields and forwards everything else untouched.
The proxy can run on the same machine as the client (simplest, most secure) or on a remote server reached over an SSH tunnel (useful if you want it always-on or shared). Both layouts are covered.
Prerequisites
- A machine to run the proxy: Python 3.10+ on Linux, macOS, or Windows.
- An Anthropic API key.
- GitHub Copilot CLI (installed in a later step).
- If the proxy will run on a remote server: SSH access to it.
Step 1 — The proxy
Save the following as strip_sampling_proxy.py. It is a transparent streaming reverse proxy: it removes temperature, top_p, and top_k from JSON request bodies, forwards everything else as-is, and asks the upstream not to compress responses (so the streamed bytes are always readable).
A note on the accept-encoding: identity line: without it, the upstream may gzip the response, and forwarding compressed bytes through a streaming proxy is easy to get wrong (you end up with garbled, non-UTF-8 output). Requesting an uncompressed response keeps the proxy simple and correct. The bandwidth cost is negligible for this use.
Running it locally
If the proxy will live on the same machine as Copilot, you're nearly done:
Skip ahead to Step 5. For a remote, always-on deployment, continue with Step 2.
Step 2 — Deploy on a Linux server
These commands target a Debian/Ubuntu-style server; adjust the package manager for your distro.
Update and install Python tooling:
Create a dedicated, unprivileged service user and a home for the code:
Place strip_sampling_proxy.py at /opt/strip-proxy/strip_sampling_proxy.py (upload it, or paste it via a here-doc). Then build an isolated virtualenv and install dependencies:
Create a hardened systemd unit at /etc/systemd/system/strip-proxy.service:
Enable and start it, then confirm it's healthy:
Firewall / security: keep the proxy bound to 127.0.0.1 and do not open its port to the internet. On a cloud VM, restrict inbound rules to SSH only; the client reaches the proxy through the SSH tunnel in the next step. This matters because the proxy forwards your API key in the request header — keeping it off the public internet protects that key in transit.
Step 3 — Connect over an SSH tunnel
This forwards a local port on your machine to the proxy on the server, so the client can talk to localhost:8787 as if the proxy were local.
Fix key-file permissions
SSH refuses a private key that other accounts can read.
On Linux/macOS:
On Windows (PowerShell), use icacls instead of chmod:
Add an SSH config entry
In ~/.ssh/config (on Windows: C:\Users<you>.ssh\config):
Replace <ssh-user> with your server's login (commonly ubuntu, ec2-user, admin, or debian, depending on the image). The ServerAlive* settings make SSH detect a dropped link and exit so a supervisor can reconnect; ExitOnForwardFailure makes it fail loudly if the local port is already taken.
Test the tunnel
Open the tunnel (it stays silent and open on success — that's expected):
In a second terminal, hit the forwarded port. A clean JSON authentication error from Anthropic means the whole path works:
If you instead get unreadable/garbled bytes, your proxy is an older version missing the accept-encoding: identity line from Step 1.
Step 4 — Keep the tunnel running
A manual ssh -N window dies when closed or when the network blips. Make it persistent.
Windows (Task Scheduler)
Create a reconnect loop, e.g. at C:\Users<you>.ssh\tunnel.ps1:
Register it as a logon task:
Then make it run without a visible window by switching the task to the S4U logon type (run PowerShell as Administrator for this command):
Start it and confirm it's Running:
With S4U, the task runs in the background as your user (so it can read your key and known_hosts) but with no desktop window to pop up or accidentally close. Accept the host key once with a manual ssh -N copilot-proxy first, so the unattended task doesn't stall on the prompt.
Linux / macOS
Use autossh for the same auto-reconnect behavior:
To start it at login, wrap that in a systemd --user service (Linux) or a launchd agent (macOS).
Step 5 — Point GitHub Copilot CLI at the proxy
As of mid-2026, the in-IDE Copilot plugins (VS Code's Anthropic provider, the JetBrains plugin) don't expose a custom base URL, so they can't be routed through a proxy. Copilot CLI can: it supports a custom base URL with the anthropic provider type, which means the strip proxy works as-is, with no request-format translation.
Install the CLI (requires Node 18+):
Set the provider environment variables. Use http://127.0.0.1:8787 (no /v1 suffix for the anthropic provider type — the client appends /v1/messages itself).
On Linux/macOS:
On Windows, set them permanently with setx (user scope), then open a new terminal:
setx writes to the registry and only affects newly launched processes — reopen your terminal (and fully restart your IDE if you run the CLI in its embedded terminal) so the values are picked up. For the API key specifically, prefer user scope over machine scope (/M) so it isn't readable by other accounts on the host. To keep the key out of the registry entirely, set it per-session in a permission-restricted launcher script instead.
The two MAX_*_TOKENS values should match the model's real limits (Opus 4.8 supports a large context window and output budget; check current model docs for exact figures). Without them, the CLI warns that the model isn't in its built-in catalog and falls back to conservative defaults — harmless, but it caps your usable context.
Step 6 — Verify
Launch copilot and give it a real task (read a file, make an edit). If it completes with tool calls and no temperature 400, the fix is working end to end: the client sends a request, the proxy strips the deprecated fields, and Anthropic accepts it.
Troubleshooting & notes
- Garbled / non-UTF-8 responses: the proxy is forwarding a compressed body without the matching header. Ensure the
accept-encoding: identityline is present (Step 1). ssh -N"hangs" with no output: that's success —-Nopens no remote shell, so there's nothing to print. Verify with thecurltest. Usessh -v -N copilot-proxyto watch the handshake.- Tunnel connects but a window keeps popping up (Windows):
-WindowStyle Hiddendoesn't fully hide an interactive task; switch the task to S4U (Step 4) to run it windowless. - "Model not in built-in catalog" (Copilot CLI): informational; set the
MAX_*_TOKENSvars to silence it and unlock the full context window. github-mcp-serverconnection warning: expected when not signed into GitHub under BYOK. It only disables GitHub-side features (Code Search,/delegate, the GitHub MCP server) and doesn't affect the model. Sign into GitHub if you want them.- Dynamic server IP: cloud VMs often get a new public address each time they stop and start. Use a static/reserved IP, or update
HostNamein your SSH config after a restart. - This is a workaround. It exists because the client injects a deprecated parameter you can't disable. If that's fixed upstream, the proxy is no longer needed — and if you only need things working quickly, an older model that still accepts
temperatureavoids the issue entirely. ```