Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Abstract

This guide explains how to use the DeepSeek Harness (dsh) agent in the course environment — what the supporting packages do, how to pick a model provider (DiveAI, LiteLLM, or your own custom endpoint), and which parts of Jupyter must be restarted for a change to take effect.

The DeepSeek Harness (dsh) is an agentic coding assistant you can use from your Jupyter server. It is the agent that reads your task, plans, and runs tools (read/write files, run shell, execute code) against an LLM provider (DiveAI, LiteLLM, or a custom endpoint).

This page is about how the pieces fit together and how to configure which model dsh talks to — not about how to write specs (see Agentic Coding).

There are two small Jupyter packages that make dsh available in your pod:

PackageRole
jupyter-dsh-proxyAdds the “DeepSeek Harness” launcher tile that opens the dsh web UI in a new tab.
dsh-openai-shimA tiny OpenAI-compatible proxy that sits between dsh and the model endpoint and fixes the two request parameters that break against non-DeepSeek models.

How it is wired

The dsh web server (dsh web) is started once at pod boot on a fixed loopback port (default 3080). jupyter-dsh-proxy does not start a second copy — it registers a jupyter-server-proxy tile that simply forwards the browser to the already-running instance:

browser  →  jupyter-server-proxy (/dsh/)  →  dsh web (127.0.0.1:3080)
dsh web  →  dsh-openai-shim (127.0.0.1:8090)  →  model endpoint (DiveAI / LiteLLM / custom)

You open it from the JupyterLab launcher tile, or directly at /dsh/ in your server URL (e.g. https://dive.cs.cityu.edu.hk/cs1302a_26a/user/<you>/dsh/). The same dsh instance is shared with the VS Code extension.

Why the shim exists

dsh’s bundled deepseek-official provider was written for the DeepSeek API and sends two things that general endpoints (Socrates / sglang) reject:

  1. reasoning_effort: "high" — Socrates only accepts xhigh / medium / low, so a raw request fails with HTTP 400: Unexpected reasoning effort high.

  2. A very large default max_tokens — combined with a long conversation it can exceed the model’s context window, failing with HTTP 400: Requested token count exceeds the model's maximum context length.

The dsh-openai-shim is the single place that fixes both:

ParameterWhat the shim does
reasoning_effortmaps high → medium (default map mode; can drop or turn off)
max_tokensclamps it to the provider’s token_cap (auto-discovered per endpoint)

Everything else (auth headers, streaming, /models, tool calls) passes through unchanged. This is also why, when a long task runs out of context, the message reads as an output-token limit — the shim is reporting the model’s real ceiling (see Model Providers and the debug report for the full mechanism).

Choosing a model provider: dsh-proxy

Your choice of upstream is persisted in ~/.dsh/proxy.conf (on your NFS home, so it survives pod restarts). The dsh-proxy command manages it:

!dsh-proxy list            # all providers; the current one is flagged with *, caps shown
!dsh-proxy show             # current provider + upstream + effective token cap (key masked)

Switch to one of the providers the deployment provides (the names you see in list):

!dsh-proxy use litellm      # switch to the LiteLLM provider
# !dsh-proxy use diveai     # or the DiveAI provider

The deployment’s providers (diveai, litellm) are refreshed automatically on every notebook start by dsh-proxy sync, which reads the endpoint + key from the pod environment (DIVEAI_API_BASE/_KEY, LITELLM_API_BASE/_KEY). That means key rotation or an endpoint move is picked up for you — and it never overwrites a custom provider you added.

Adding your own (custom) endpoint

You are not limited to the two provided providers. dsh-proxy use <name> --base <url> [--key <key>] adds any OpenAI-compatible endpoint and switches to it:

# Example: point at your own sglang / vLLM / OpenAI-compatible server
# !dsh-proxy use myendpoint --base https://myhost.example/v1 --key sk-...

On the first use, the shim auto-discovers the completion-token cap by probing the new endpoint’s GET /v1/models (reading max_completion_tokens / max_model_len). You do not have to know the model’s limit. If the probe cannot reach the endpoint (or it advertises no limit), the cap stays at the default and the shim self-heals at request time: if the upstream rejects a request with an “N too large … at most M tokens” 400, the shim reads M, lowers the cap, retries once, and saves M. Override with --token-cap N (or --no-discover to skip the probe).

The full command set:

dsh-proxy list      # all providers, current flagged (*), caps shown
dsh-proxy use NAME  # switch to an existing provider
dsh-proxy use NAME --base URL [--key KEY] [--token-cap N]   # add + switch
dsh-proxy show      # current provider + upstream + effective cap
dsh-proxy sync      # (run at pod start) refresh deployment providers
dsh-proxy status    # is the shim daemon running?
dsh-proxy restart   # restart the shim daemon from proxy.conf

Using dsh from VS Code (code-server)

The same dsh is available inside VS Code — no separate install. The dsh web server is started once at pod boot, and the VS Code extension simply connects to that same already-running instance (it only auto-starts its own dsh web if nothing is listening yet, so the two entry points never fight over the port). You get the same agent, the same ~/.dsh/proxy.conf provider choice, and the same sessions as the web tile.

To use it:

  1. Open VS Code from JupyterLab: File → New Launcher → VSCode (or use the vscode() link generator in any lab notebook).

  2. Open the DeepSeek Harness view (activity-bar icon) and start a conversation — it is the same dsh you use at /dsh/, sharing your provider and sessions.

  3. Because it lives in the editor, dsh can see your workspace files, active file / selection, and terminal, so you can point it at specific files and let it edit them in place.

Provider is shared. Whatever you chose with dsh-proxy use (web or CLI) is the one the VS Code extension uses — the choice lives in ~/.dsh/proxy.conf, not in the interface. If a switch looks stale in VS Code, reload the editor window (or restart the shim with dsh-proxy restart).

What you must restart for a change to take effect

This is the part that trips people up. There are two separate running pieces, and a change takes effect only once the right one is restarted:

  1. The shim daemon — dsh-proxy use writes ~/.dsh/proxy.conf and restarts the running shim automatically, so a provider switch is applied immediately. (There is no lazy auto-start in the request path — dsh makes plain HTTP calls to the loopback port, so the daemon must already be pointing at the new endpoint.) If it ever gets stuck, run dsh-proxy restart (or dsh-proxy status to check it is up).

  2. The dsh web UI — the web server reads the provider at request time via the shim, so in most cases you do not need to restart the browser tab. But if you see a provider change not reflected (e.g. you edited ~/.dsh/proxy.conf by hand, or the shim daemon is stale), reload the dsh tab (or restart the web UI). As a clean reset, restarting your whole Jupyter server re-runs the boot hook that starts dsh web fresh.

Rule of thumb: dsh-proxy use handles the shim restart for you. If something still looks stale, reload the dsh tab first; if that does not fix it, restart the Jupyter server.

Troubleshooting

  • dsh-proxy status says the shim is not running → dsh-proxy restart.

  • A provider switch seems ignored → reload the dsh tab; then dsh-proxy restart; then restart the Jupyter server.

  • “Output token limit reached” on a long task → this is context exhaustion, not a bug; compact the conversation or scope the task smaller (see Model Providers).

  • HTTP 400: Unexpected reasoning effort → you are bypassing the shim and hitting the endpoint directly; make sure dsh points at the shim, not the raw endpoint.

Related: Model Providers (getting your LiteLLM key, Hermes provider config), Hermes Agent, Agentic Coding.