Mhmd7-7/dsh-ai-model-hub ↗★ 0

dsh-ai-model-hub

DeepSeek Harness plugin and library for local AI models: a capability catalog, router, runtime manager, and real engine adapters. The agent names a capability; the hub selects, starts, and calls a suitable model. 适合需要统一调度和运行本地多模态(文本、图像、3D等)模型的人群。

Package
dsh-ai-model-hub
Compatibility
Unverified
Harness peer range
>=0.1.5-rc.2 <0.3.0
Cordis peer range
^4.0.2
Version
0.6.0
Last updated
Oct 13, 2026

Install

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:Mhmd7-7/dsh-ai-model-hub

dsh-ai-model-hub

A modular local AI model ecosystem for DeepSeek Harness (DSH).

DSH is the agent — it reasons, plans, calls tools, and orchestrates workflows. It is not the model runtime. The specialised models (text, image, 3D, audio, video) are external and local, reached through a capability interface. DSH never learns how to launch Stable Diffusion, which Python file starts a mesh generator, or how a given engine manages its process. It only asks:

What capabilities are available?

Everything below that question is this project's job.

┌──────────────────────────────────────────────────────────────────────┐
│  DeepSeek Harness                        agent reasoning, planning,  │
│  ─────────────────                       tool invocation, workflows  │
│                                                                      │
│      tools: invoke_model · list_models · list_capabilities ·         │
│             get_model_status · start_model · stop_model · …          │
└───────────────────────────────┬──────────────────────────────────────┘
                                │  dsh-ai-model-hub DSH plugin
                                │  (the ONLY DSH-aware code)
┌───────────────────────────────▼──────────────────────────────────────┐
│  ModelHub facade                        invokeModel({ capability })  │
│  ┌────────────────┬──────────────────┬───────────────────────────┐   │
│  │ Capability     │ Model Router     │ Runtime Manager           │   │
│  │ Catalog        │ deterministic    │ lifecycle · health ·      │   │
│  │ registry +     │ capability-first │ idle timeout · resources  │   │
│  │ validation     │ selection        │                           │   │
│  └────────────────┴──────────────────┴───────────────────────────┘   │
│  ┌──────────────────────────────┬────────────────────────────────┐   │
│  │ Model Adapters               │ Artifact Store                 │   │
│  │ openai_compatible · http_json│ durable, typed, addressable    │   │
│  │ comfyui · three_d ·          │ text/image/audio/video/3D/…    │   │
│  │ mock (tests only)            │                                │   │
│  └──────────────────────────────┴────────────────────────────────┘   │
└───────────────────────────────┬──────────────────────────────────────┘
                                │  spawn (argv, never a shell string)
┌───────────────────────────────▼──────────────────────────────────────┐
│  Local engines: Ollama · llama.cpp · A1111/Forge · ComfyUI ·         │
│  TRELLIS · Hunyuan3D · Stable Fast 3D · TripoSR · …                  │
└──────────────────────────────────────────────────────────────────────┘

Status

Live as a DSH profile plugin. The package installs as one unit — dsh plugin add mounts it, so the hub is composed on every boot — and it serves real local engines only: Ollama for text, ComfyUI / A1111 / Forge for images, llama.cpp for a second text engine, and any local image-to-3D Gradio app for meshes. There are no mock models anywhere in the shipped catalogs and no mock fallback at runtime: a wrong model name or a stopped engine is a loud error (or a cold start), never fixture output.

The whole architecture — catalog → routing → runtime → adapter → artifact → chained workflow — is covered by the test suite, which uses an in-process mock adapter as a test double. That adapter is not a model: nothing ships it in a catalog, and no deployment can reach it by accident.

PhaseScopeStatus
1Full architecture, DSH plugin, tests✅ done
2Real local text model (Ollama / llama.cpp / vLLM / LM Studio)✅ done — openai_compatible adapter ships
3Real local image model (A1111 / ComfyUI)✅ done — http_json and comfyui adapters ship
4Real local 3D model✅ done — three_d adapter ships; see docs/three-d.md
5Runtime lifecycle + resource-aware routing✅ done — the machine is probed and routed against
6Multi-model workflows✅ done

Phase 2 needs no new code: the openai_compatible adapter is implemented, and config/examples/real-models.example.json contains ready-to-copy Ollama and llama.cpp entries. Phase 3 is implemented by two adapters, because the two engine families are genuinely different:

  • http_json — engines that answer one request with a finished image: AUTOMATIC1111, Forge, and stable-diffusion.cpp's sd-server. It POSTs the familiar /sdapi/v1/txt2img body and decodes the base64 images that come back.
  • comfyui — ComfyUI takes an API-format node graph, not a prompt endpoint. Each explicitly configured workflow declares capabilities, exact input bindings and a typed output selector. The adapter treats graph internals as opaque, edits only declared inputs, queues on /prompt, polls /history, and retrieves the declared output. No checkpoint or saved-workflow enumeration creates providers.

Phase 4 is three_d: one adapter that speaks the shape the local 3D ecosystem actually has — a Gradio queue API or a JSON HTTP route, one or two calls, a mesh file at the end — so TRELLIS, Hunyuan3D, Stable Fast 3D, and TripoSR are catalog entries rather than code. It writes a typed model_3d artifact (GLB, GLTF, OBJ, STL, or PLY, sniffed from the bytes), and a discoverer verifies a declared engine against the API surface it actually exposes before publishing anything.

Phase 5's remaining gap is closed: ModelHub now probes RAM, VRAM, free VRAM, and disk, re-measures on demand, and routes against measured headroom — so a model that would not fit beside what is already loaded is refused with the shortfall in the message instead of crashing inside the engine.

All adapters are registered by default. See docs/adding-a-model.md, docs/three-d.md, and the protocol templates in config/workflows/.


Install

One command, on a machine that already has Node ≥ 22.6 and DeepSeek Harness:

# into the profile behind `dsh web` — the normal case
dsh plugin --profile web add github:Mhmd7-7/dsh-ai-model-hub

This package is the plugin: it declares dsh.bundle.patch, so dsh plugin add installs it and appends dsh-ai-model-hub to dsh.profile.bundles. The profile composes that bundle on every boot, which is what makes the plugin live, not merely installed. No profile file is edited by hand and no cordis.patch.yml has to be written.

Then restart DeepSeek Harness and ask:

List the available AI model capabilities.
What you wantCommand
Another profiledsh plugin --profile hubtest add github:Mhmd7-7/dsh-ai-model-hub
A pinned releasedsh plugin --profile web add github:Mhmd7-7/dsh-ai-model-hub#v0.6.0
A published copydsh plugin --profile web add dsh-ai-model-hub
A checkout you are editingnode --no-deprecation scripts/install-plugin.mjs --profile web

The last one links the working tree instead of copying it, so the plugin loads your sources; run npm run build there first if you edited anything under src/ or dsh-plugin/.

install.ps1 and install.sh remain one-line wrappers for the first row, and keep their flags (-Profile, -Ref, -Repository, -SkipDoctor):

irm https://raw.githubusercontent.com/Mhmd7-7/dsh-ai-model-hub/main/install.ps1 | iex
curl -fsSL https://raw.githubusercontent.com/Mhmd7-7/dsh-ai-model-hub/main/install.sh | sh

To remove an installation:

dsh plugin --profile web remove dsh-ai-model-hub

Which DeepSeek Harness versions this runs on

The plugin tracks the DSH 0.x line rather than a single release:

Supported@deepseek-ai/dsh* >=0.1.5-rc.2 =0.1.5-rc.2
takes another catalog, and the last section deliberately asks for a capability
nobody serves, to show what a refusal looks like.

npm run demo:3d needs nothing installed. It starts a stand-in 3D engine inside the example and runs the whole real path against it — discovery, health, resource-aware routing, a two-step Gradio protocol, and a .glb written to disk — then prints every HTTP request the engine saw, to make the boundary concrete. To point it at TRELLIS instead, swap the stand-in for your catalog entry; the three capability calls are identical. See docs/three-d.md.

B. Give the capability to the DeepSeek Harness agent

# Installs into the 'web' profile (the one behind `dsh web`), then verifies.
npm run install:plugin

# ...or target another profile:
node --no-deprecation scripts/install-plugin.mjs --profile 

Then restart DeepSeek Harness and ask the agent:

List the available AI model capabilities.

Checking an installation

npm run doctor                          # inspects: is it loadable, and if not, why not
node scripts/smoke.mjs --profile web    # acts: applies the plugin and lists what it registered

doctor inspects and reports; smoke actually runs the plugin against a real cordis context and prints the tools it registered. Use smoke when you want proof rather than a checklist:

Registered tools:
  check_model_health   explain_routing    get_model_status   invoke_model
  list_artifacts       list_capabilities  list_models        start_model
  stop_model           refresh_model_discovery
Catalog: model hub ready: 2 model(s), 2 capability(ies) from …/config/models.json

Note on flags. npm run forwards flags to the script, but npm 12 parses --profile as its own config flag and fails. Use the direct node scripts/smoke.mjs --profile form for a non-default profile.

If DSH fails to boot after installing

If the harness dies with:

invalid plugin, expect function or object with an "apply" method, received object

then the row cordis.patch.yml inserts is pointing at something that is not a plugin. In this package that can only happen if the row's name was changed away from the bare package name: dsh-ai-model-hub resolves to the package's . export, which is the plugin (lib/dsh-plugin/index.js, exporting name/inject/apply/Config). The hub library lives behind the dsh-ai-model-hub/library subpath instead, precisely so the two cannot be confused.

The row has two names, and they are easy to conflate: id is the row's name in the composed tree (what a profile's own cordis.patch.yml uses to override or disable it), while name is the module specifier the loader imports. Keep name bare — a subpath such as dsh-ai-model-hub/plugin would load the host half but silently drop the Web UI half, because DSH's client module system only resolves a row's package manifest from a bare specifier. cordis.patch.yml documents this in pla