dsh-model-as-tool
Verified@try-works/dsh-model-as-tool Β· v0.4.8 Β· MIT Β· Web UI
Install Desert Ant Labs on-device models as DSH tools and skills, with per-platform capability gating
Install
dsh plugin add @try-works/dsh-model-as-tool Confirm the layer applied with dsh --profile default --dump-config β see the install guide.
Source
Tags
Readme
dsh-model-as-tool
Install on-device models as DSH tools and skills, with per-platform capability gating. Ships with the Desert Ant Labs catalog.
A DSH agent gets a real tool for every model that can run in its process, a skill that teaches it when to reach for that tool, and an honest explanation for every model that cannot run β instead of a tool that fails at call time.
What it does
The plugin composes six layers:
- Catalog (
catalog/desert-ant-models.json) β all 18 Desert Ant models, their inputs, outputs, language counts and the npm package that runs them. - Capability resolver (
src/capability.ts) β decides, per model, whether it can actually run in this process, and why not when it cannot. - Adapters (
src/adapters/) β lazily import a model package and invoke it. - Transports (
src/transport.ts) β reach a model this machine cannot run: through the Desert Ant CLI, or through a bridge on a machine that can. - Registrar (
src/registrar.ts) β turns each reachable model into adefineTooldefinition registered onctx.tools. - Skills (
src/skills.ts+catalog/playbooks.json) β publishes one skill per registered tool describing when to use it, when not to, and how.
Nothing is imported from a model package at plugin load, so a deployment that installs none of them still starts cleanly and reports exactly what is missing.
Tools it registers
| Tool | Model | Runs on Windows x64 | Notes |
|---|---|---|---|
lang_detect |
Tongue | yes | Pure JavaScript, 2 MB model inside the package, no network |
transcribe_audio |
Voz | yes | Needs onnxruntime-node; ~349 MB weights download on first use |
model_tools |
β | yes | Lists every catalogued model, and installs/removes tools |
The other 16 catalog models are reported by model_tools with the exact reason
they cannot run, for example:
- [unavailable] redact (`redact_pii`): On-device redaction that strips personal
data as you type, in 27 languages, with restore support.
why not: Redact has no prebuilt native build for win32-x64; @desert-ant-labs/redact/native
ships one for linux-x64, linux-arm64 and darwin-arm64 only.
Reaching the other 16 models
A model only needs a route, not a rewrite. Two routes cover the rest.
The CLI (macOS and Linux)
Every shipping model is desertant <verb> β¦ --json, so wherever the CLI is
installed the plugin will drive it. Nothing to configure β it is detected on
PATH:
curl -fsSL https://raw.githubusercontent.com/Desert-Ant-Labs/desert-ant-cli/main/install.sh | sh
That immediately makes Redact, Emo, Gist, Clear, Ear, Moderator, Shapes, Align, Tongue and Voz callable on that machine.
The bridge (an Apple machine, for Apple-only models)
Title and Uhm run only on Apple silicon. Run the reference bridge there and point the plugin at it:
# on the Mac
node scripts/desert-ant-bridge.mjs --token "$(openssl rand -hex 16)"
- id: model-tools
config:
remote:
endpoint: http://mac-studio.local:8787
token: <the token>
suggest_title then registers here with route: remote, and the existing
catalog entry, parameter schema and skill apply unchanged. The bridge is a thin
wrapper over the CLI; it binds to loopback and requires a token. The plugin
does not host anything β the licence forbids re-hosting the models as a
service, so the bridge must be your own machine.
Installing tools at run time
model_tools actions: list, installed, describe <id>, enable <id>,
disable <id>, reset [<id>].
Enable and disable are remembered across restarts. A plugin config states
the deployment default; enable/disable record the user's choice on top of
it:
disablealways wins, so a user can turn off something the config ships.enableadds to the config selection, so a user can turn something on without editing YAML.resetforgets the choice and makes the configuration authoritative again.
Choices are stored as JSON at <DSH_HOME>/model-as-tool/state.json, written
through a temporary file and a rename so a crash cannot leave a truncated
document that reads as "everything is gone".
{ "enabled": ["voz"], "disabled": ["tongue"] }
The plugin writes its own state file rather than rewriting your
cordis.patch.yml: a rewrite there would fight the profile's reload and could
clobber comments you wrote. Point it elsewhere with stateFile, or set
persist: false for the earlier session-scoped behaviour.
Enabling a model that cannot run here fails with the resolver's reason and nothing is written β persisting a failed enable would install it silently on the next start.
Install
The package is a DSH bundle: package.json declares
dsh.bundle.patch: ./cordis.patch.yml, and that patch is the single insert
row a profile mounts. Install it with plugin_manager's install_bundle
action, or copy the row from cordis.patch.yml into the
profile's own patch file.
The package builds itself on install: prepare runs tsc from src/ into
lib/, which is the entry point main and exports advertise. A registry
tarball ships lib/ prebuilt by prepack, so a consumer needs no toolchain.
Model packages are optional dependencies: install only the ones you want.
npm i @desert-ant-labs/tongue # language detection, works everywhere
npm i @desert-ant-labs/voz onnxruntime-node # transcription on Windows/Linux/macOS
The plugin never bundles or re-hosts model weights.
What gets downloaded, and when
Three separate things arrive at three separate times. Measured sizes are from a Windows x64 install of this package.
1. The plugin itself β ~58 kB, from npm, at install. lib/, the two catalog
JSON files, cordis.patch.yml and this README. It contains no model weights
and no inference runtime.
2. The model SDK packages β from npm, at install, only if you asked for them.
They are optionalDependencies, so a failed or skipped download does not fail the
install; the capability resolver simply reports the model as unavailable.
| Package | Size on disk | Contains |
|---|---|---|
@desert-ant-labs/tongue |
2.1 MB | The model itself β tongue_int8.bin (2.0 MB) ships inside the tarball |
@desert-ant-labs/voz |
44.2 MB | The WebAssembly runtime (VozWeb.wasm), not the weights |
onnxruntime-node |
287.1 MB | The prebuilt inference engine for this platform |
3. The weights β from Hugging Face, on first call, not at install. Each SDK pins one revision and verifies the download, then caches it. Voz fetches about 367 MB on its first transcription:
~/.cache/desert-ant-models/desert-ant-labs/voz 367 MB (first call)
Tongue never downloads anything: its model is inside the npm package.
Point an SDK at a pre-populated folder to run offline (each adapter accepts a
directory), and set HF_TOKEN for a gated repo. Because the licence forbids
redistribution, the plugin never bundles or mirrors weights β it downloads them
the way the vendor intends, once, into the vendor's own cache.
Install cost is real, so it is opt-out
Installing with the optional dependencies present pulls roughly 333 MB before any model runs, and a first Voz call adds 367 MB more. If that is unwanted, install the plugin with them skipped and add only what you use:
npm i @try-works/dsh-model-as-tool --omit=optional
npm i @desert-ant-labs/tongue # 2 MB, and its model is included
Watch out for the other model packages. They ship prebuilt native cores for
linux-x64, linux-arm64 and darwin-arm64 inside one tarball β roughly 50 MB
each β so @desert-ant-labs/redact is ~166 MB of which the great majority is
Linux and macOS binaries that can never load on Windows. Installing one on
Windows buys ~130 MB that cannot run.
Development
npm install # devDependencies: tsc, tsx, and the two model packages
npm run link:dsh # point @deepseek-ai/* peers at a DSH checkout
npm run verify # typecheck -> build -> 35 tests -> built-artifact check
link:dsh exists because @deepseek-ai/* are peer dependencies β DSH
supplies them at runtime, so locally they must be pointed at a checkout:
node scripts/link-dsh.mjs --checkout /path/to/deepseek-harness
Run it again after any npm install: npm prunes anything in node_modules it
does not own, which includes those links.
npm run verify ends with verify:built, which loads lib/index.js β resolved
through the package's own main, under plain Node with no TypeScript loader β
and runs a real inference. That is the artifact DSH loads, so it is the only
build whose behaviour proves the plugin is installable; passing tests against
src/ under tsx does not.
| Command | Purpose |
|---|---|
npm run demo |
Mount the plugin on a real context and print what it registered |
npm run gating |
Print the resolved route for every catalogued model |
npm run gen-docs |
Regenerate the data-derived docs from the catalog |
npm run bridge |
Run the reference bridge for an Apple/Linux machine |
Tests always mount through tests/helpers.ts, which points the durable state at
a throwaway directory. That is not cosmetic: the plugin writes user choices into
DSH_HOME by default, so an unisolated test would edit the developer's real
configuration and a later test would read those edits as a user decision.
Configuration
- id: model-tools
name: '@try-works/dsh-model-as-tool'
config:
models: [] # empty = every runnable model; or list ids, e.g. [tongue]
exclude: [] # ids to drop after `models`
exposeUnavailable: false # true registers tools that will fail at call time
registerSkills: true
registerControlTool: true
persist: true # remember enable/disable across restarts
# stateFile: /path/to/state.json # default <DSH_HOME>/model-as-tool/state.json
allowNpm: true # false forces the CLI/bridge routes
cli:
enabled: true # use the Desert Ant CLI when it is on PATH
command: desertant
remote:
endpoint: '' # a bridge on a machine that can run what this one cannot
token: ''
# catalogFile: /path/to/other-catalog.json
# playbookFile: /path/to/other-playbooks.json
Platform support
This is the part that matters most, because Desert Ant's Node prebuilds cover
linux-x64, linux-arm64 and darwin-arm64 β not win32-x64.
| Tier | Models | How |
|---|---|---|
| Runs in plain Node everywhere | Tongue | Pure JS, no WASM, no inference runtime |
| Runs where ONNX Runtime runs | Voz | onnxruntime-node ships win32-x64 binaries |
| Prebuilt for linux/darwin only | Redact, Emo, Gist, Clear, Ear, Moderator, Shapes, Align | /native subpath |
| Apple only (Core ML / MLX) | Title, Uhm | Swift SDK; no JS or Kotlin SDK |
| Closed beta, no SDK | Schemer, Toxic, Who, Eye, Face | Weights on Hugging Face, nothing ships them |
The browser/WASM entry of the LiteRT models explicitly refuses to run in plain Node ("needs a browser/Worker environment"), so it is not a fallback.
Licensing
The Desert Ant Labs models are under the Source-Available License 1.0 β not an open-source license. Inference is unlimited and free below 100,000 monthly active devices per platform, per model; above that a commercial license is required. Attribution ("Powered by Desert Ant Labs", linked) is required, and the models may not be redistributed or re-hosted as a standalone product or service.
That is exactly why this plugin is an installer/wrapper: it loads the official npm packages locally and never ships, mirrors or proxies the weights.
Tests
npm run verify # from the repository root
The suite boots the plugin on a real Cordis context with the shipping
ToolRuntime, SystemPrompt and SkillRegistry, then drives the registered
tools through ctx.tools.execute β including a real Tongue inference. The
transport suite injects its command runner and HTTP poster, so the CLI and bridge
failure paths are covered without a process or a socket.
Design notes
- See docs/model-as-tool-architecture.md for the full design.
- See docs/adding-a-model.md to add a model.
- See docs/model-tool-playbook.md for the per-model use cases, tool shapes and skill content.