feat(dsh): add DeepSeek Harness wrap support - #2994
Conversation
PR governanceThis PR follows the template and is marked ready for human review. |
JerrettDavis
left a comment
There was a problem hiding this comment.
There is one blocking routing/credential-boundary issue on the latest head.
_resolve_openai_upstream() checks _is_deepseek_request(...) before _resolve_openai_upstream_base(...) (lines 1721–1723). That reverses the established precedence of the explicit x-headroom-base-url override. A custom OpenAI-compatible gateway request using a deepseek-* model—or carrying dsh’s identifying header—will be sent to DEEPSEEK_API_URL instead of the caller-selected gateway. Because the inbound authorization headers are forwarded, this can also send a gateway-scoped credential to the public DeepSeek endpoint.
Please resolve the explicit base URL first, then use DeepSeek detection only as the fallback before OPENAI_API_URL. Add regression cases for both detection forms with x-headroom-base-url present (DeepSeek model prefix and dsh header) so this credential boundary stays pinned.
The rest of the provider registration, launch environment, proxy compatibility check, and CLI structure looks coherent. Two small documentation cleanups can ride with the fix: add dsh to README’s supported unwrap list, and keep the runtime/docs wording aligned about the pnpm dsh fallback.
JerrettDavis
left a comment
There was a problem hiding this comment.
The requested routing correction is complete on the latest head. _resolve_openai_upstream now honors an explicit x-headroom-base-url before either DeepSeek signal, with regressions covering both a deepseek-* model and the harness header. This preserves custom/private gateway routing while retaining the intended public-DeepSeek fallback. The README wrap/unwrap lists and package-manager wording are also corrected.
I reran the affected routing, runtime, wrap CLI, registry, and backend regression modules: 74 passed. Focused Ruff and git diff --check also pass.
Description
Adds
headroom wrap dsh/unwrap dshso DeepSeek Harness (dsh) sessions get their traffic compressed through the proxy. dsh speaks OpenAI-compatible chat-completions, so this reuses the existing OpenAI handler — the only new routing is a DeepSeek upstream target and a check that sendsdeepseek-*models (or anything carrying dsh'sx-deepseek-harness-user-idheader) to DeepSeek instead of OpenAI.Closes # (new provider, no issue)
Type of Change
Changes Made
headroom/providers/dsh/package (build_launch_env,resolve_dsh_command, install env builder).deepseekupstream target wired throughregistry.py,ProxyConfig,server.py, and theproxyCLI (DEEPSEEK_TARGET_API_URLenv /--deepseek-api-urlflag)._is_deepseek_request+_resolve_openai_upstream).wrap dsh/unwrap dshcommands —web+headlessprofile,--command,--deepseek-api-url; launch-env only, no durable config.wiki/dsh.md,llms.txt.Testing
pytest)ruff check .)ruff format --check .)mypy)Test Output
Real Behavior Proof
uv sync --extra dev --extra proxy, dsh v0.1.0-rc.6 (npm i -g @deepseek-ai/dsh).uv run python smoke_dsh.py(mock DeepSeek upstream, no key) — posts adeepseek-v4-flashchat completion through the proxy withx-deepseek-harness-user-id: anon; anduv run headroom wrap dsh --profile headless "..."for the live path.POST /v1/chat/completionswith the dsh header intact, and the client got a 200. WithOPENAI_TARGET_API_URLpointed at a dead port, the request still succeeded — so it hit DeepSeek, not OpenAI.Runtime Rollout Safety
deepseekdefaults tohttps://api.deepseek.com; existing providers untouched.headroom unwrap dsh.headroom unwrap dsh(proxy teardown only).Review Readiness
Checklist
CHANGELOG.mdAdditional Notes
One known gap, documented in
wiki/dsh.mdrather than implemented: abaseURLhardcoded in dsh's settings/cordis.yml overrides$DEEPSEEK_BASE_URLand would silently bypass the proxy. The env-var path works (including a pre-existingDEEPSEEK_BASE_URL, whichwrap dshcaptures as the upstream). Durable settings-patching or a fail-loud guard would be the follow-up if that edge case matters.