Introduction

When deploying DeepSeek Harness (DSH) behind a corporate gateway, a common obstacle arises: the egress gateway validates the request’s user-agent, rejecting requests that do not contain a specified brand identifier. Meanwhile, DSH’s LLM adapter forcibly writes its own attribution user-agent, which cannot be bypassed by simply changing a field in the configuration file.

dsh-llm-headers solves this problem: it is a DSH plugin that injects your configured headers into requests sent to LLM providers at the HTTP layer. Below is an explanation of its principles, installation methods, and typical usage.

What is it

dsh-llm-headers injects HTTP Headers for DeepSeek Harness’s custom LLM API requests, with the typical use case being rewriting the user-agent. The code is released under the MIT license, current version 0.1.0, and hosted in the GitHub repository QiE2035/dsh-llm-headers.

Its key property is provider-agnostic: DSH’s LLM adapters (dsh-llm-deepseek, dsh-llm-pi-ai) all send model requests via the global fetch, so the plugin only needs to wrap fetch once; one configuration applies to all LLM providers simultaneously.

Core Features

How it works: On load, the plugin wraps globalThis.fetch. It applies configured headers item-by-item via set() only for requests matching urlPatterns (overwriting headers with the same name, including the adapter’s forced attribution user-agent), and passes others through unchanged.

Three configuration entry points, real-time application:

  1. Web UI: The plugin registers the Config schema as the llm-headers user configuration namespace. The Settings page automatically renders the edit form. It takes effect immediately after saving (applies: live, no restart needed);
  2. cordis.yml: As the base layer configuration;
  3. settings.yaml: A backup channel; saving triggers a hot reload.

Values saved via the UI take precedence over the config in cordis.yml.

Default Safety:

  • By default, it is lazy (empty headers), so it does not rewrite any requests;
  • Empty strings in urlPatterns are ignored and will not mistakenly match all URLs;
  • When the request URL cannot be classified (e.g., a Request instance across realms), it passes through unchanged;
  • On uninstall, it only restores the original value if it is still the current fetch wrapper, ensuring it does not break subsequent wrappers.

Concurrency Protection: The Web UI save carries the last read revision (optimistic concurrency). If the configuration is modified elsewhere, it rejects with a conflict prompt and automatically refreshes; a “Restore Defaults” button is provided to clear user settings and revert to the cordis.yml config and schema defaults.

Installation and Activation

The release form is a bundle. The installation command is as follows, which appends llm-headers to the specified profile’s bundle layer:

dsh plugin --profile <name> add /path/to/llm-headers

After installation, the plugin is in a lazy state (empty headers) by default and will not rewrite any requests; it only takes effect when explicitly configured.

For development and debugging, you can load local source code by path. Add the following to any cordis.yml (or patch overlay):

- insert:
    - id: llm-headers
      name: /absolute/path/to/llm-headers/src/index.ts

Typical Usage

Configuring via cordis.yml

The following configuration rewrites the user-agent to opencode/1.0 and only applies to requests containing /chat/completions:

- id: llm-headers
  name: dsh-llm-headers
  config:
    headers:
      user-agent: opencode/1.0
    urlPatterns:
      - /chat/completions

Explanation of the two fields:

Field Type Default Description
headers Record<string, string> {} The headers to inject; overwrites same-name headers, empty means no injection
urlPatterns string[] ['/chat/completions'] URL substring matching rules; injection occurs if any match

Configuring via Web UI

After installing to a profile containing a Web interface:

  1. Open Web UI → Settings page;
  2. Find the LLM Headers card in ‘Plugins’ → ‘Plugin Config’;
  3. Fill in headers and urlPatterns and save. It writes to the user-settings document and takes effect in real-time.

Configuring via settings.yaml

When not using the Web UI, you can also write this in settings.yaml:

llm-headers:
  headers:
    user-agent: opencode/1.0
  urlPatterns:
    - /chat/completions

It takes effect immediately upon saving without a restart.

End-to-end Verification

The repository comes with e2e/echo-server.mjs, which logs received request headers and returns a simulated streaming response to confirm that the configured headers really reach the provider:

node e2e/echo-server.mjs
pnpx @deepseek-ai/dsh --profile headless --patch <overlay.yml> "Reply ok"

Start the echo server first, then run a headless task; the server terminal should print the user-agent carried by that request (i.e., the value configured in the overlay). The repository also scripts this process as pnpm test:e2e, which automatically backs up and restores settings.yaml; running it requires DEEPSEEK_API_KEY.

Use Cases and Considerations

Suitable scenarios:

  • The deployment environment has a gateway validating user-agent, requiring replacement with the deployer’s brand (whitelabel replacement);
  • Need to attach a custom header uniformly to all LLM requests;
  • Want to adjust request headers at runtime via the Web UI without modifying configuration files or restarting.

Precautions before use:

  • The user-agent override only takes effect when the header is explicitly configured in headers; otherwise, the attribution is retained as-is;
  • Multiple plugins wrapping fetch simultaneously will overwrite each other; avoid stacking with other plugins doing similar things;
  • Runtime environment requires Node ^22.19.0 || >=24.0.0;
  • The ./client entry point (lib/client.js) is an internal interface for the host Web module loader and is not intended for third parties, nor are type declarations published.

Additional reminder: The plugin runs with the permissions of the current dsh process. You should review the source code and license before installing. This plugin code is under the MIT license and source code is public; you can review it yourself before enabling it.

Summary

dsh-llm-headers focuses on a specific task: injecting custom headers into DSH’s LLM requests at the HTTP layer. It is lazy by default, takes effect in real-time, and cleans up cleanly on uninstall. It is a small, concrete tool for resolving gateway and deployment customization issues under DSH’s “everything is a plugin” philosophy.

Repository: https://github.com/QiE2035/dsh-llm-headers

Community Directory: https://www.skillhub.cn/plugins/QiE2035/dsh-llm-headers (Community-maintained independent site, no official affiliation with DeepSeek or Magic Quadrant)