Skip to content

dsh-api-server

Verified

@wattetheria/dsh-api-server · v0.1.1 · Apache-2.0

OpenAI-compatible HTTP API plugin for DeepSeek Harness, implemented by Wattetheria

Install

dsh plugin add @wattetheria/dsh-api-server

Confirm the layer applied with dsh --profile default --dump-config — see the install guide.

Source

Creators

Readme

@wattetheria/dsh-api-server

OpenAI-compatible HTTP API routes for a running DeepSeek Harness Web profile.

This package is implemented and maintained by the Wattetheria project. It is an integration plugin, not an official DeepSeek Harness package.

This is intentionally the API Server path, not DSH's separate ACP/JSON-RPC stdio bridge. Wattetheria connects to the HTTP URL owned by the running DSH Web profile.

What It Provides

The plugin attaches to the HTTP server that DSH Web already starts:

  • GET /v1/models
  • POST /v1/chat/completions

The request is handled by the existing DSH Agent and Session services. DSH keeps ownership of the model adapter, tools, session history, persistence, and agent lifecycle. This package only translates the OpenAI HTTP shape into a DSH turn and translates the result back.

It deliberately does not add a second process or a second transport configuration. There is no command, arguments, transport, working directory, or separate port in this plugin. The host and port remain the responsibility of the DSH Web profile's existing webServer.

Install

From the repository root during local development:

npx @deepseek-ai/dsh plugin --profile web add .

The package declares a DSH bundle, so installing it into the web profile adds the route automatically. Restart the DSH Web process after installation.

After the package is published, install it by name:

npx @deepseek-ai/dsh plugin --profile web add @wattetheria/dsh-api-server

This integration targets the DSH Web profile. It should not be added to the headless profile because that profile does not mount the HTTP webServer.

Start

The API is available whenever the DSH Web profile is running:

npx @deepseek-ai/dsh web

By default the endpoint is:

http://127.0.0.1:3080/v1

The DSH Web profile still owns the bind address and port. Use its normal Web flags to change them.

Configuration

The plugin has only integration-specific settings:

Setting Default Meaning
path /v1 URL prefix for the two routes
bearerToken generated Optional explicit HTTP bearer token override
provider DSH current default Provider route used for newly created sessions
model DSH current default Model used when a request omits model

On its first start, the plugin generates a 256-bit bearer token and stores it as DSH_OPENAI_SERVER_BEARER_TOKEN in DSH's managed $DSH_HOME/.credentials.yaml file. The existing value is reused on later starts and is never overwritten. This token authenticates the HTTP server; it is separate from any API key DSH uses to call an LLM provider.

Load the generated token into the current shell when testing the endpoint:

TOKEN="$(awk -F': ' '/^DSH_OPENAI_SERVER_BEARER_TOKEN:/{print $2}' \
  "${DSH_HOME:-$HOME/.dsh}/.credentials.yaml")"

An inherited environment value can be supplied instead of the generated token:

export DSH_OPENAI_SERVER_BEARER_TOKEN='replace-with-a-strong-random-token'
npx @deepseek-ai/dsh web

An explicit bearerToken plugin setting has the highest priority. Otherwise, the token is resolved through DSH credentials on every request, so credential rotation takes effect without restarting the server.

Requests

List the models exposed by the current DSH provider:

curl http://127.0.0.1:3080/v1/models \
  -H "Authorization: Bearer $TOKEN"

Send a stateless completion:

curl http://127.0.0.1:3080/v1/chat/completions \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "deepseek-v4-flash",
    "messages": [{"role": "user", "content": "Say hello in one sentence."}]
  }'

Enable streaming with the normal OpenAI flag:

curl -N http://127.0.0.1:3080/v1/chat/completions \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "deepseek-v4-flash",
    "stream": true,
    "messages": [{"role": "user", "content": "Count from one to three."}]
  }'

For a persistent DSH conversation, send an opaque session id in X-DSH-Session-ID:

curl http://127.0.0.1:3080/v1/chat/completions \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'X-DSH-Session-ID: wattetheria-demo' \
  -d '{
    "model": "deepseek-v4-flash",
    "messages": [{"role": "user", "content": "Remember the word watt."}]
  }'

The same id can be sent on the next request. The response also returns it as X-DSH-Session-ID. When no session id is supplied, the server creates and disposes a fresh DSH agent for that request and renders the supplied OpenAI messages as one prompt.

Current Boundary

The first version accepts text messages and text content-part arrays. Images, tool-result message parts, and client-side OpenAI tool-call orchestration are rejected at the HTTP boundary. DSH's own configured tools remain available to the agent because the request runs through the native DSH Agent loop.

max_tokens is applied when a new DSH session is created. A persistent session keeps the options with which that agent was created. The current DSH model/provider selection is used by default, so the API route follows the same model configuration as the running Web profile.

Project Links

Development

npm install
npm run check

The implementation uses TypeScript and Node.js, matching the language and npm/Cordis plugin conventions used by DeepSeek Harness.