Skip to content
dsh.fish
Bundle

dsh-plugin-openai-api

OpenAI-compatible /v1/chat/completions (streaming and non-streaming) and /v1/models endpoint on the DSH web server: one DSH agent session per (API key, X-Agent-Preset) pair.

Source
paulalesius
License
MIT
Updated
Updated 6 days ago

Readme

# dsh-plugin-openai-api

<p align="center"><img src="./banner.jpg" alt="dsh-plugin-openai-api banner"/></p>

An OpenAI-compatible endpoint on a running `dsh web` server:

```
GET  /v1/models
POST /v1/chat/completions        (non-streaming and SSE streaming)
```

## Installation

Install the plugin:

```bash
dsh plugin --profile web add /path/to/openai-api
```

(From a DSH source checkout, the same command is `pnpm dsh plugin …`.
A plain path links the source, so edits are picked up on restart. Fresh
checkout of this repo: recreate `node_modules` first —
`ln -s /path/to/deepseek-harness/apps/cli/node_modules node_modules`.)

Uninstall the plugin:

```bash
dsh plugin --profile web remove dsh-plugin-openai-api
```

Restart `dsh web` after either.

## Configuration

Append to `~/.dsh/profiles/web/cordis.patch.yml` (the install ships
`disabled: true`):

```yaml
- id: openai-api
  disabled: false
  config:
    model: default
    apiKeys:
      - local-key
```

The `config` block replaces the plugin's defaults wholesale. Set
`disabled: true` to switch the endpoint off. Restart `dsh web` after
changes. All keys are optional:

| key | default | what it does |
| --- | --- | --- |
| `model` | `default` | The model id advertised at `/v1/models`. A request's `model` (absent, or this id) → the host's default model selection; any other id is passed through to the session. |
| `provider` | host default | The provider route created sessions use. |
| `apiKeys` | unset (no auth) | Non-empty array of client keys. When set, a request must present one of them (`Authorization: Bearer <key>`), else 401. A key identifies the caller; it does not select the preset. |
| `cwd` | the `dsh web` process's working directory | Working directory for created sessions. Must start with `/`. |

## Using the API

The contract is OpenAI's — it just works.

```js
import OpenAI from 'openai'

const client = new OpenAI({
  baseURL: 'http://127.0.0.1:3080/v1',
  apiKey: 'local-key', // one of the config's apiKeys
})

// The agent preset rides a header; omit it for the default preset.
const preset = { 'X-Agent-Preset': 'custom-agent-preset' }

const reply = await client.chat.completions.create(
  {
    model: 'default',
    messages: [
      { role: 'user', content: 'What are you? ' },
      { role: 'assistant', content: "I'm a DSH agent." },
      { role: 'user', content: 'Write a haiku about that.' },
    ],
  },
  { headers: preset },
)
console.log(reply.choices[0].message.content)
```

The same, without an SDK (the `Bearer` header only when you set
`apiKeys`):

```sh
curl -s http://127.0.0.1:3080/v1/chat/completions \
  -H 'content-type: application/json' -H 'Authorization: Bearer local-key' \
  -H 'X-Agent-Preset: custom-agent-preset' \
  -d '{"messages":[{"role":"user","content":"hello"}]}'
```

## Headers

### `X-Agent-Preset`

The agent preset id the session joins — any id in
`~/.dsh/.agent-presets/`, plus the shipped presets.

- Absent → the default preset (`standard`).
- Unknown id → 400 with the roster; repeated or comma-joined → 400.
- Resolved at session creation only: the same (key, preset) pair always
  resumes the same session; a different value is a different session.

Install

dsh plugin --profile web add github:paulalesius/dsh-openai-api#e4e47559248bd051d0bd7f86010c6633dc17f1af

Profile: web

Source