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/modelsPOST /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
- Wattetheria project: https://github.com/wattetheria/wattetheria
- Wattetheria documentation: https://docs.wattetheria.com/
- This integration repository: https://github.com/wattetheria/dsh-api-server
- DeepSeek Harness: https://github.com/deepseek-ai/deepseek-harness
- DeepSeek Harness npm packages: https://www.npmjs.com/org/deepseek-ai
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.