* fix(provider): match MiniMax and Venice base URLs by hostname, not substring
The credential-mirroring chains route xAI, Cloudflare and Xiaomi through their
exact-hostname predicates (isXaiBaseUrl, isCloudflareBaseUrl,
isXiaomiMimoBaseUrl), but the MiniMax and Venice branches were left on raw
baseUrl.toLowerCase().includes('minimax') / includes('api.venice.ai') even
though isMiniMaxBaseUrl / isVeniceBaseUrl already exist. A proxy or lookalike
host (minimax-proxy.example.com, api.venice.ai.evil.com) therefore mirrors the
profile key into MINIMAX_API_KEY / VENICE_API_KEY; for MiniMax, providerAutoDetect
then reroutes it to the real api.minimax.io the user never configured. Route all
four sites through the hostname predicates, consistent with the neighbouring
providers.
* fix(provider): centralize dedicated-key mirroring across the profile lifecycle
The host-detected dedicated credential mapping (xAI, MiniMax, Venice,
MiMo) was reconstructed independently in three places and had drifted:
- The startup env builder's strict-env branch returned before any of
these mirrors, so a keyed generic OpenAI-compatible profile on a
canonical Venice/MiniMax host persisted only OPENAI_API_KEY and
relaunched without its dedicated credential; the fallback branch had
no MiniMax mirror at all and matched MiMo by substring.
- isProcessEnvAlignedWithProfile never checked MINIMAX_API_KEY, so once
that key drifted after activation the env was still considered aligned
and applyActiveProviderProfileFromConfig skipped reapplying — leaving
MiniMax's dedicated-credential transport misrouted.
Introduce getHostDedicatedCredentialEnv as the single source of truth
for the exact-host (and, where available, route) credential mapping, and
route live application, both startup-persistence branches, and the
alignment check through it. Lookalike hosts still receive no dedicated
key.
* fix(provider): carry MiniMax dedicated key through launch reconstruction
buildLaunchEnv rebuilt the startup environment from a fixed dedicated-key
carry-over list that omitted MINIMAX_API_KEY, so a clean restart of a keyed
MiniMax profile retained the generic OpenAI variables but dropped the
dedicated credential. The MiniMax client only enters its native setup while
MINIMAX_API_KEY is present, so the persisted profile did not deliver the
intended restart behavior.
Add MINIMAX_API_KEY to the carry-over contract alongside the other
native-client vendor keys (MIMO/VENICE), preserving the same
shell-over-persisted precedence. The client's own hostname/route detection
gates activation, so an ambient key stays inert in an unrelated session.
Regressions reconstruct the launch environment from a saved profile with an
empty shell and assert both the surviving credential and the selected
env-only route (via resolveEnvOnlyProviderRouteId), not just the persisted
file: canonical MiniMax carries and reselects, a live shell key overrides
the persisted one, and a generic profile never synthesizes the credential.
* fix(provider): preserve keyless credential reconciliation
* fix(provider): scope MiniMax launch credentials to the active route
* fix(provider): admit saved Venice and MiMo keys only on their routes
* test(provider): document saved dedicated-key precedence
* fix(provider): restore test globals and scope profile docs
* fix(provider): keep explicit MiniMax route credentials across reconcile
Reconcile reapply rebuilt a generic OpenAI profile from the hostname only, so a launch that had already kept CLAUDE_CODE_PROVIDER_ROUTE_ID=minimax on a proxy lost MINIMAX_API_KEY when another env field drifted. Reapply now reuses that same-profile route instead of URL substring matching.
* fix(provider): preserve saved credentials in pane teammates
---------
Co-authored-by: jatmn <the@jat.mn>
* fix(api): retry explicitly throttled OpenAI-compatible 403s
* fix(api): allow explicit throttling messages that name an API key
* fix(api): distinguish OAuth throttling from token faults
* fix(api): preserve auth precedence and remote throttle retry headers
Match account, key, and token faults across clause wording instead of a
20-character credential window. Preserve plural faults and structured
error codes while allowing valid key and OAuth throttle messages.
Keep classified throttle-403s out of the infrastructure-auth retry
exception so their existing header and quota checks apply in remote mode.
Cover actual shim retries, guidance, credential recovery, and native CCR
retry behavior.
* fix(api): distinguish credential predicates across comma clauses
Keep unrelated disabled features from vetoing a valid-key throttle while
preserving actual key faults continued through relative descriptions or
parentheticals. Normalize only matching boundaries and retain raw error
text. Cover the reported retry path and baseline credential-fault cases.
* fix(api): require fault predicates in credential continuations
An adverb alone does not connect a later disabled feature to an API key.
Require an auxiliary/adverb sequence to reach the fault directly, while
preserving relative descriptions and parentheticals of the credential.
Cover the unrelated-subject regression through the real retry loop.
* fix(api): exclude routing host metadata from quota detection
Keep quota keyword matching on provider evidence and category markers,
without allowing the configured hostname to suppress throttle retries.
Preserve the original error message for diagnostics and host consumers.
Cover real 403/429 retry paths and genuine quota/no-retry controls.
* fix(api): preserve throttle fault precedence and retry categories
* fix(api): recognize qualified credential absence
* fix(lsp): synchronize document versions across restarts
Track each open document by server generation and advance versions only after lifecycle notifications are delivered. This prevents replacement language servers from serving requests before receiving current file contents.
* fix(lsp): harden restart synchronization
Preserve active document URIs across Windows path aliases and coordinate connection replacement, failed startup cleanup, cross-generation retries, and shutdown with in-flight document work.
* fix(lsp): settle restart lifecycle races
Make failed starts and transport loss settle pending work, prevent obsolete generations from publishing responses, and keep diagnostics activity on the opened document identity.
* fix(lsp): preserve lifecycle generation boundaries
* fix(lsp): bound document recovery lifecycle
* test(lsp): harden lifecycle regression coverage
* fix(lsp): bound failed startup recovery
* test(lsp): harden lifecycle failure coverage
* test(lsp): restore current-main compatibility and isolation
---------
Co-authored-by: jatmn <the@jat.mn>
buildOllamaChatBody() never set a top-level `think` field on outgoing
requests. Ollama's hybrid-thinking models (e.g. Qwen3.x) interpret the
field's absence as thinking enabled, so every Ollama request ran in
thinking mode regardless of --effort, with no way to disable it. The
existing client-side thinking filter only hides the trace from display —
the model still generates the full reasoning chain either way, so the
latency cost was paid regardless of whether it was visible.
Mirrors the effort-handling already implemented for the Anthropic/Gemini
paths just above this function: no --effort specified maps to
think: false; an explicit effort level is passed through (xhigh/max/
ultracode collapse to Ollama's "high", matching its three-tier scale).
Measured on qwen3.6:35b-a3b-coding (Ollama, Apple Silicon):
- Before: 15-21s per trivial response, full visible reasoning trace
- After: ~1.3s via the raw Ollama API with think=false, ~5s through the
full CLI (Node startup + OpenAI<->Ollama format conversion overhead)
- No visible reasoning trace in either case after the fix
* chore(deps): upgrade @sentry/node to 11.9.0 (M-14)
* fix(sentry): omit hostname from sanitized error reports
* test(sentry): cover nonessential-traffic opt-out on its own
* fix(sentry): bound Sentry flush before shutdown exit
* fix(sentry): leave tracesSampleRate unset so spans stay disabled
* fix(shutdown): include Sentry drain in failsafe budget and test pending-flush exits
* chore(deps): upgrade undici to 8.12.3 (M-12)
* fix(proxy): honor lowercase no_proxy precedence and refresh cached bypass rules
* docs(proxy): clarify TLS options for NO_PROXY bypasses and CONNECT targets
* fix(proxy): clear CA and mTLS caches on structured I/O bypass updates
Also close the global test dispatcher in undiciFetch cleanup and document lowercase-first no_proxy precedence for fetch/undici.
* fix(proxy): refresh TLS and proxy state on certificate-only environment updates
* chore(deps): replace cli-highlight with a highlight.js ANSI renderer
* fix(highlight): key fallback highlight cache by Chalk level
Also correct the CONTRIBUTING highlighting note and move the qrcode
retention test and note out of this change.
* fix(proxy): pass runtime CA and mTLS options to the target TLS connection behind CONNECT proxies
* test(proxy): isolate CONNECT tests from leaked axios mocks
* chore(deps): update https-proxy-agent to 9.1.0
* test(proxy): isolate CONNECT test from leaked axios mocks
* test(proxy): avoid global axios module registration
* test(proxy): exercise createAxiosInstance in CONNECT test
The custom-gateway lifecycle case initializes the process-global model string table with OpenAI aliases. Teardown did not clear it, so later getAgentModel haiku and fast-mode Opus tests in the same serial process resolved stale gpt-4o aliases. Reset the table in lifecycle setup and teardown.
Capture detached real module exports before mocking and restore secure
storage and device-flow modules after each refresh-on-401 test. This
prevents shared-process credential mocks from breaking provider setup and
saved-profile startup tests in randomized serial runs.
* test: synchronize retention policy phases
* test: verify cleanup policy hook ordering
Record the rejecting policy hook and threshold phase in the cleanup fixture,
and assert that the hook runs first while the throttle lock is held.
Preserve existing policy outcome and snapshot assertions.
* test: prove cleanup reruns remove newly completed sessions