Back to home@staff-os

dsh-dify

Dify agent and knowledge-base capability for the DeepSeek Harness

Stars
0
Language
TypeScript
Created
Aug 19, 2026
Updated
Aug 19, 2026
GitHub repo

Introduction

dsh-dify

English | 中文

Dify agent and knowledge-base capability for the DeepSeek Harness. It gives the agent two tools — dify_chat that calls a Dify agent app, and dify_retrieve that queries a Dify knowledge base (dataset) for relevant chunks.

Design

The package follows the Harness three-role capability pattern: one seam, one provider, one consumer — shipped as one package with four plugin entry points (the fourth is the configuration page over the same values), so a profile can override, replace, or drop any single role without touching the others.

RoleModulePlugin nameResponsibility
Service Definitionsrc/index.ts@deepseek-ai/dsh-difyOwns ctx.dify: provider registry, order-independent selection
Service Providersrc/http.ts@deepseek-ai/dsh-dify/httpCalls Dify Service API (/chat-messages, /datasets/{id}/retrieve), resolves credentials, normalizes results
Consumersrc/tool.ts@deepseek-ai/dsh-dify/toolThe model-facing tools: dify_chat, dify_retrieve — schema, prompt guidance, presentation
Consumersrc/config.ts@deepseek-ai/dsh-dify/configThe person-facing configuration page over the same settings and credential seams

The provider and the consumer depend only on the Service Definition, never on each other. Replacing the backend means replacing one row:

- id: dify-http
  name: 'your-own-dify-provider'

Prerequisites

  1. A running Dify instance — self-hosted or cloud. Defaults to https://api.dify.ai/v1.
  2. A Dify API key — create one for your app in Dify.
  3. A Dify agent app — for dify_chat to call.
  4. A Dify knowledge base (dataset) — for dify_retrieve to query. At least one dataset id must be configured.

Install

dsh plugin --profile web add "github:staff-os/dsh-dify#main"

dsh plugin add forwards the source to pnpm as-is, so any pnpm-recognized source works:

dsh plugin --profile web add link:/path/to/dsh-dify   # local development

lib/ is committed, so no build script runs at install time and pnpm needs no build allowance. Restart dsh web afterwards, then verify the four rows landed:

dsh --profile web --dump-config | grep dify

Configure

Three ways in, one set of values. The configuration page is the easy one; the environment and the YAML rows remain exactly what they were.

The configuration page

With dsh web running, open http://127.0.0.1:3080/dify (whatever port the web surface printed). It edits the endpoint, the default dataset, and the tool timeout, and it stores the API key through the credential service — the key never reaches a settings file, and the field reports only whether one is configured.

Every field is leave empty to inherit: the box holds your own override, the placeholder names the value in effect without one. Clearing a box is how a field goes back to inheriting the composition row, the environment variable, or the schema default. Test connection runs one live chat so a saved endpoint can be confirmed rather than assumed.

The page is served on loopback only, whatever dsh web --host binds, because it reads deployment configuration and writes a credential. Move it with the row's path, or take it out entirely:

# ~/.dsh/profiles/web/cordis.patch.yml
- id: dify-config
  disabled: true

Environment variables

Set the environment the plugin reads — no YAML and no page needed for the common case:

export DIFY_API_KEY=app-xxx
export DIFY_BASE_URL=https://your-dify-host/v1     # optional, defaults to https://api.dify.ai/v1
export DIFY_DATASET_ID=dataset_id_1                 # required for dify_retrieve unless set in YAML
export DIFY_USER=end-user-id                        # optional, defaults to dsh-user

The API key resolves through the DSH credentials service when one is mounted (~/.dsh/.credentials.yaml), and through the launch environment otherwise. Never inline a key in a config file.

@deepseek-ai/dsh-dify (seam)

ConfigDefaultDescription
providerautoProvider id to pin. Unset auto-selects when exactly one is usable. Also $DSH_DIFY_PROVIDER.

@deepseek-ai/dsh-dify/http (provider)

ConfigDefaultDescription
apiKeyLiteral key. Prefer apiKeyEnv.
apiKeyEnvDIFY_API_KEYCredential reference resolved per operation.
baseURL$DIFY_BASE_URLhttps://api.dify.ai/v1Endpoint base; /chat-messages and /datasets/... are appended.
user$DIFY_USERdsh-userDify end-user identifier sent on every request.
datasetId$DIFY_DATASET_IDDefault dataset for dify_retrieve.

@deepseek-ai/dsh-dify/tool (consumer)

ConfigDefaultDescription
timeoutMs60000Cooperative per-call timeout budget. Read at registration: a change applies at the next start.

@deepseek-ai/dsh-dify/config (configuration page)

ConfigDefaultDescription
path/difyPathname the page and its JSON endpoints (/state, /save, /probe) are served under.

Call flow

dify_chat

  1. The model calls dify_chat with a query and optional conversationId.
  2. The tool validates it and calls ctx.dify.chat({ query, conversationId }, signal).
  3. The seam selects the usable provider and forwards the request.
  4. The provider posts to POST /chat-messages in blocking mode.
  5. The tool renders the answer text.

dify_retrieve

  1. The model calls dify_retrieve with a query and optional datasetId.
  2. The tool validates it and calls ctx.dify.retrieve({ query, datasetId }, signal).
  3. The seam selects the usable provider and forwards the request.
  4. The provider posts to POST /datasets/{id}/retrieve and normalizes records[].
  5. The tool renders the chunks as cited text plus structured metadata.

An empty result is a result: the tool tells the model the knowledge base has nothing relevant and not to invent a citation.

Develop

pnpm install
pnpm test        # vitest
pnpm typecheck   # tsc --noEmit
pnpm build       # tsdown → lib/{index,http,tool,config}.js

lib/ is committed; rebuild and commit it with any src/ change.

Dify API reference

Troubleshooting

SymptomCauseFix
DIFY_SCOPE_MISSINGNo dataset id in scopeSet datasetId or $DIFY_DATASET_ID
DIFY_PROVIDER_CREDENTIAL_MISSINGNo key for the credential referenceSet $DIFY_API_KEY, or match apiKeyEnv to your credentials key
DIFY_PROVIDER_UNAUTHORIZEDDify rejected the keyReissue the key in Dify
DIFY_PROVIDER_UNAVAILABLEProvider row missing or its options invalidCheck --dump-config for the dify-http row
DIFY_PROVIDER_AMBIGUOUSTwo usable providers registeredPin one with the seam's provider
dify_chat / dify_retrieve absent from the tool listBundle not loadeddsh --dump-config | grep dify; restart dsh web
The page answers NOT_LOOPBACKReached over a LAN addressOpen it from the host itself, or tunnel the port
The page answers SETTINGS_CONFLICTThe settings document moved since the page loadedReload the page and reapply

Known limitations

  • Blocking mode only — no SSE streaming. The full response is awaited.
  • dify_chat does not forward file inputs or vision attachments.
  • dify_retrieve does not support multi-dataset search or attachment_ids.
  • The configuration page does not list available Dify apps or datasets for selection.